upload android base code part6
This commit is contained in:
parent
421e214c7d
commit
4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions
61
android/system/core/libsync/Android.bp
Normal file
61
android/system/core/libsync/Android.bp
Normal file
|
@ -0,0 +1,61 @@
|
|||
ndk_headers {
|
||||
name: "libsync_headers",
|
||||
from: "include/ndk",
|
||||
to: "android",
|
||||
srcs: ["include/ndk/sync.h"],
|
||||
license: "NOTICE",
|
||||
}
|
||||
|
||||
ndk_library {
|
||||
name: "libsync",
|
||||
symbol_file: "libsync.map.txt",
|
||||
first_version: "26",
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "libsync_defaults",
|
||||
srcs: ["sync.c"],
|
||||
local_include_dirs: ["include"],
|
||||
export_include_dirs: ["include"],
|
||||
cflags: ["-Werror"],
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "libsync",
|
||||
defaults: ["libsync_defaults"],
|
||||
}
|
||||
|
||||
llndk_library {
|
||||
name: "libsync",
|
||||
symbol_file: "libsync.map.txt",
|
||||
export_include_dirs: ["include"],
|
||||
}
|
||||
|
||||
// libsync_recovery is only intended for the recovery binary.
|
||||
// Future versions of the kernel WILL require an updated libsync, and will break
|
||||
// anything statically linked against the current libsync.
|
||||
cc_library_static {
|
||||
name: "libsync_recovery",
|
||||
defaults: ["libsync_defaults"],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "sync_test",
|
||||
defaults: ["libsync_defaults"],
|
||||
gtest: false,
|
||||
srcs: ["sync_test.c"],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "sync-unit-tests",
|
||||
shared_libs: ["libsync"],
|
||||
srcs: ["tests/sync_test.cpp"],
|
||||
cflags: [
|
||||
"-g",
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
"-Wno-missing-field-initializers",
|
||||
"-Wno-sign-compare",
|
||||
],
|
||||
clang: true,
|
||||
}
|
190
android/system/core/libsync/NOTICE
Normal file
190
android/system/core/libsync/NOTICE
Normal file
|
@ -0,0 +1,190 @@
|
|||
|
||||
Copyright (c) 2012-2017, The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
69
android/system/core/libsync/include/android/sync.h
Normal file
69
android/system/core/libsync/include/android/sync.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* sync.h
|
||||
*
|
||||
* Copyright 2012 Google, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __SYS_CORE_SYNC_H
|
||||
#define __SYS_CORE_SYNC_H
|
||||
|
||||
/* This file contains the legacy sync interface used by Android platform and
|
||||
* device code. The direct contents will be removed over time as code
|
||||
* transitions to using the updated interface in ndk/sync.h. When this file is
|
||||
* empty other than the ndk/sync.h include, that file will be renamed to
|
||||
* replace this one.
|
||||
*
|
||||
* New code should continue to include this file (#include <android/sync.h>)
|
||||
* instead of ndk/sync.h so the eventual rename is seamless, but should only
|
||||
* use the things declared in ndk/sync.h.
|
||||
*
|
||||
* This file used to be called sync/sync.h, but we renamed to that both the
|
||||
* platform and NDK call it android/sync.h. A symlink from the old name to this
|
||||
* one exists temporarily to avoid having to change all sync clients
|
||||
* simultaneously. It will be removed when they've been updated, and probably
|
||||
* after this change has been delivered to AOSP so that integrations don't
|
||||
* break builds.
|
||||
*/
|
||||
|
||||
#include "../ndk/sync.h"
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct sync_fence_info_data {
|
||||
uint32_t len;
|
||||
char name[32];
|
||||
int32_t status;
|
||||
uint8_t pt_info[0];
|
||||
};
|
||||
|
||||
struct sync_pt_info {
|
||||
uint32_t len;
|
||||
char obj_name[32];
|
||||
char driver_name[32];
|
||||
int32_t status;
|
||||
uint64_t timestamp_ns;
|
||||
uint8_t driver_data[0];
|
||||
};
|
||||
|
||||
/* timeout in msecs */
|
||||
int sync_wait(int fd, int timeout);
|
||||
struct sync_fence_info_data *sync_fence_info(int fd);
|
||||
struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info,
|
||||
struct sync_pt_info *itr);
|
||||
void sync_fence_info_free(struct sync_fence_info_data *info);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* __SYS_CORE_SYNC_H */
|
88
android/system/core/libsync/include/ndk/sync.h
Normal file
88
android/system/core/libsync/include/ndk/sync.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_SYNC_H
|
||||
#define ANDROID_SYNC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <linux/sync_file.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#if __ANDROID_API__ >= __ANDROID_API_O__
|
||||
|
||||
/* Fences indicate the status of an asynchronous task. They are initially
|
||||
* in unsignaled state (0), and make a one-time transition to either signaled
|
||||
* (1) or error (< 0) state. A sync file is a collection of one or more fences;
|
||||
* the sync file's status is error if any of its fences are in error state,
|
||||
* signaled if all of the child fences are signaled, or unsignaled otherwise.
|
||||
*
|
||||
* Sync files are created by various device APIs in response to submitting
|
||||
* tasks to the device. Standard file descriptor lifetime syscalls like dup()
|
||||
* and close() are used to manage sync file lifetime.
|
||||
*
|
||||
* The poll(), ppoll(), or select() syscalls can be used to wait for the sync
|
||||
* file to change status, or (with a timeout of zero) to check its status.
|
||||
*
|
||||
* The functions below provide a few additional sync-specific operations.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Merge two sync files.
|
||||
*
|
||||
* This produces a new sync file with the given name which has the union of the
|
||||
* two original sync file's fences; redundant fences may be removed.
|
||||
*
|
||||
* If one of the input sync files is signaled or invalid, then this function
|
||||
* may behave like dup(): the new file descriptor refers to the valid/unsignaled
|
||||
* sync file with its original name, rather than a new sync file.
|
||||
*
|
||||
* The original fences remain valid, and the caller is responsible for closing
|
||||
* them.
|
||||
*/
|
||||
int32_t sync_merge(const char *name, int32_t fd1, int32_t fd2);
|
||||
|
||||
/**
|
||||
* Retrieve detailed information about a sync file and its fences.
|
||||
*
|
||||
* The returned sync_file_info must be freed by calling sync_file_info_free().
|
||||
*/
|
||||
struct sync_file_info *sync_file_info(int32_t fd);
|
||||
|
||||
/**
|
||||
* Get the array of fence infos from the sync file's info.
|
||||
*
|
||||
* The returned array is owned by the parent sync file info, and has
|
||||
* info->num_fences entries.
|
||||
*/
|
||||
static inline struct sync_fence_info* sync_get_fence_info(const struct sync_file_info* info) {
|
||||
// This header should compile in C, but some C++ projects enable
|
||||
// warnings-as-error for C-style casts.
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
return (struct sync_fence_info *)(uintptr_t)(info->sync_fence_info);
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
/** Free a struct sync_file_info structure */
|
||||
void sync_file_info_free(struct sync_file_info *info);
|
||||
|
||||
#endif // __ANDROID_API__ >= __ANDROID_API_O__
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* ANDROID_SYNC_H */
|
1
android/system/core/libsync/include/sync/sync.h
Symbolic link
1
android/system/core/libsync/include/sync/sync.h
Symbolic link
|
@ -0,0 +1 @@
|
|||
../android/sync.h
|
28
android/system/core/libsync/libsync.map.txt
Normal file
28
android/system/core/libsync/libsync.map.txt
Normal file
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# Copyright 2017 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
LIBSYNC {
|
||||
global:
|
||||
sync_merge; # introduced=26
|
||||
sync_file_info; # introduced=26
|
||||
sync_file_info_free; # introduced=26
|
||||
sync_wait; # vndk
|
||||
sync_fence_info; # vndk
|
||||
sync_pt_info; # vndk
|
||||
sync_fence_info_free; # vndk
|
||||
local:
|
||||
*;
|
||||
};
|
35
android/system/core/libsync/sw_sync.h
Normal file
35
android/system/core/libsync/sw_sync.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* sw_sync.h
|
||||
*
|
||||
* Copyright 2013 Google, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __SYS_CORE_SW_SYNC_H
|
||||
#define __SYS_CORE_SW_SYNC_H
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* sw_sync is mainly intended for testing and should not be compiled into
|
||||
* production kernels
|
||||
*/
|
||||
|
||||
int sw_sync_timeline_create(void);
|
||||
int sw_sync_timeline_inc(int fd, unsigned count);
|
||||
int sw_sync_fence_create(int fd, const char *name, unsigned value);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* __SYS_CORE_SW_SYNC_H */
|
421
android/system/core/libsync/sync.c
Normal file
421
android/system/core/libsync/sync.c
Normal file
|
@ -0,0 +1,421 @@
|
|||
/*
|
||||
* sync.c
|
||||
*
|
||||
* Copyright 2012 Google, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <malloc.h>
|
||||
#include <poll.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <android/sync.h>
|
||||
|
||||
/* Legacy Sync API */
|
||||
|
||||
struct sync_legacy_merge_data {
|
||||
int32_t fd2;
|
||||
char name[32];
|
||||
int32_t fence;
|
||||
};
|
||||
|
||||
/**
|
||||
* DOC: SYNC_IOC_MERGE - merge two fences
|
||||
*
|
||||
* Takes a struct sync_merge_data. Creates a new fence containing copies of
|
||||
* the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the
|
||||
* new fence's fd in sync_merge_data.fence
|
||||
*
|
||||
* This is the legacy version of the Sync API before the de-stage that happened
|
||||
* on Linux kernel 4.7.
|
||||
*/
|
||||
#define SYNC_IOC_LEGACY_MERGE _IOWR(SYNC_IOC_MAGIC, 1, \
|
||||
struct sync_legacy_merge_data)
|
||||
|
||||
/**
|
||||
* DOC: SYNC_IOC_LEGACY_FENCE_INFO - get detailed information on a fence
|
||||
*
|
||||
* Takes a struct sync_fence_info_data with extra space allocated for pt_info.
|
||||
* Caller should write the size of the buffer into len. On return, len is
|
||||
* updated to reflect the total size of the sync_fence_info_data including
|
||||
* pt_info.
|
||||
*
|
||||
* pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence.
|
||||
* To iterate over the sync_pt_infos, use the sync_pt_info.len field.
|
||||
*
|
||||
* This is the legacy version of the Sync API before the de-stage that happened
|
||||
* on Linux kernel 4.7.
|
||||
*/
|
||||
#define SYNC_IOC_LEGACY_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\
|
||||
struct sync_fence_info_data)
|
||||
|
||||
/* SW Sync API */
|
||||
|
||||
struct sw_sync_create_fence_data {
|
||||
__u32 value;
|
||||
char name[32];
|
||||
__s32 fence;
|
||||
};
|
||||
|
||||
#define SW_SYNC_IOC_MAGIC 'W'
|
||||
#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0, struct sw_sync_create_fence_data)
|
||||
#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Support for caching the sync uapi version.
|
||||
//
|
||||
// This library supports both legacy (android/staging) uapi and modern
|
||||
// (mainline) sync uapi. Library calls first try one uapi, and if that fails,
|
||||
// try the other. Since any given kernel only supports one uapi version, after
|
||||
// the first successful syscall we know what the kernel supports and can skip
|
||||
// trying the other.
|
||||
|
||||
enum uapi_version {
|
||||
UAPI_UNKNOWN,
|
||||
UAPI_MODERN,
|
||||
UAPI_LEGACY
|
||||
};
|
||||
static atomic_int g_uapi_version = ATOMIC_VAR_INIT(UAPI_UNKNOWN);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int sync_wait(int fd, int timeout)
|
||||
{
|
||||
struct pollfd fds;
|
||||
int ret;
|
||||
|
||||
if (fd < 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fds.fd = fd;
|
||||
fds.events = POLLIN;
|
||||
|
||||
do {
|
||||
ret = poll(&fds, 1, timeout);
|
||||
if (ret > 0) {
|
||||
if (fds.revents & (POLLERR | POLLNVAL)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
} else if (ret == 0) {
|
||||
errno = ETIME;
|
||||
return -1;
|
||||
}
|
||||
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int legacy_sync_merge(const char *name, int fd1, int fd2)
|
||||
{
|
||||
struct sync_legacy_merge_data data;
|
||||
int ret;
|
||||
|
||||
data.fd2 = fd2;
|
||||
strlcpy(data.name, name, sizeof(data.name));
|
||||
ret = ioctl(fd1, SYNC_IOC_LEGACY_MERGE, &data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return data.fence;
|
||||
}
|
||||
|
||||
static int modern_sync_merge(const char *name, int fd1, int fd2)
|
||||
{
|
||||
struct sync_merge_data data;
|
||||
int ret;
|
||||
|
||||
data.fd2 = fd2;
|
||||
strlcpy(data.name, name, sizeof(data.name));
|
||||
data.flags = 0;
|
||||
data.pad = 0;
|
||||
|
||||
ret = ioctl(fd1, SYNC_IOC_MERGE, &data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return data.fence;
|
||||
}
|
||||
|
||||
int sync_merge(const char *name, int fd1, int fd2)
|
||||
{
|
||||
int uapi;
|
||||
int ret;
|
||||
|
||||
uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire);
|
||||
|
||||
if (uapi == UAPI_MODERN || uapi == UAPI_UNKNOWN) {
|
||||
ret = modern_sync_merge(name, fd1, fd2);
|
||||
if (ret >= 0 || errno != ENOTTY) {
|
||||
if (ret >= 0 && uapi == UAPI_UNKNOWN) {
|
||||
atomic_store_explicit(&g_uapi_version, UAPI_MODERN,
|
||||
memory_order_release);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = legacy_sync_merge(name, fd1, fd2);
|
||||
if (ret >= 0 && uapi == UAPI_UNKNOWN) {
|
||||
atomic_store_explicit(&g_uapi_version, UAPI_LEGACY,
|
||||
memory_order_release);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct sync_fence_info_data *legacy_sync_fence_info(int fd)
|
||||
{
|
||||
struct sync_fence_info_data *legacy_info;
|
||||
struct sync_pt_info *legacy_pt_info;
|
||||
int err;
|
||||
|
||||
legacy_info = malloc(4096);
|
||||
if (legacy_info == NULL)
|
||||
return NULL;
|
||||
|
||||
legacy_info->len = 4096;
|
||||
err = ioctl(fd, SYNC_IOC_LEGACY_FENCE_INFO, legacy_info);
|
||||
if (err < 0) {
|
||||
free(legacy_info);
|
||||
return NULL;
|
||||
}
|
||||
return legacy_info;
|
||||
}
|
||||
|
||||
static struct sync_file_info *modern_sync_file_info(int fd)
|
||||
{
|
||||
struct sync_file_info local_info;
|
||||
struct sync_file_info *info;
|
||||
int err;
|
||||
|
||||
memset(&local_info, 0, sizeof(local_info));
|
||||
err = ioctl(fd, SYNC_IOC_FILE_INFO, &local_info);
|
||||
if (err < 0)
|
||||
return NULL;
|
||||
|
||||
info = calloc(1, sizeof(struct sync_file_info) +
|
||||
local_info.num_fences * sizeof(struct sync_fence_info));
|
||||
if (!info)
|
||||
return NULL;
|
||||
|
||||
info->num_fences = local_info.num_fences;
|
||||
info->sync_fence_info = (__u64)(uintptr_t)(info + 1);
|
||||
|
||||
err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
|
||||
if (err < 0) {
|
||||
free(info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static struct sync_fence_info_data *sync_file_info_to_legacy_fence_info(
|
||||
const struct sync_file_info *info)
|
||||
{
|
||||
struct sync_fence_info_data *legacy_info;
|
||||
struct sync_pt_info *legacy_pt_info;
|
||||
const struct sync_fence_info *fence_info = sync_get_fence_info(info);
|
||||
const uint32_t num_fences = info->num_fences;
|
||||
|
||||
legacy_info = malloc(4096);
|
||||
if (legacy_info == NULL)
|
||||
return NULL;
|
||||
legacy_info->len = sizeof(*legacy_info) +
|
||||
num_fences * sizeof(struct sync_pt_info);
|
||||
strlcpy(legacy_info->name, info->name, sizeof(legacy_info->name));
|
||||
legacy_info->status = info->status;
|
||||
|
||||
legacy_pt_info = (struct sync_pt_info *)legacy_info->pt_info;
|
||||
for (uint32_t i = 0; i < num_fences; i++) {
|
||||
legacy_pt_info[i].len = sizeof(*legacy_pt_info);
|
||||
strlcpy(legacy_pt_info[i].obj_name, fence_info[i].obj_name,
|
||||
sizeof(legacy_pt_info->obj_name));
|
||||
strlcpy(legacy_pt_info[i].driver_name, fence_info[i].driver_name,
|
||||
sizeof(legacy_pt_info->driver_name));
|
||||
legacy_pt_info[i].status = fence_info[i].status;
|
||||
legacy_pt_info[i].timestamp_ns = fence_info[i].timestamp_ns;
|
||||
}
|
||||
|
||||
return legacy_info;
|
||||
}
|
||||
|
||||
static struct sync_file_info* legacy_fence_info_to_sync_file_info(
|
||||
struct sync_fence_info_data *legacy_info)
|
||||
{
|
||||
struct sync_file_info *info;
|
||||
struct sync_pt_info *pt;
|
||||
struct sync_fence_info *fence;
|
||||
size_t num_fences;
|
||||
int err;
|
||||
|
||||
pt = NULL;
|
||||
num_fences = 0;
|
||||
while ((pt = sync_pt_info(legacy_info, pt)) != NULL)
|
||||
num_fences++;
|
||||
|
||||
info = calloc(1, sizeof(struct sync_file_info) +
|
||||
num_fences * sizeof(struct sync_fence_info));
|
||||
if (!info) {
|
||||
free(legacy_info);
|
||||
return NULL;
|
||||
}
|
||||
info->sync_fence_info = (__u64)(uintptr_t)(info + 1);
|
||||
|
||||
strlcpy(info->name, legacy_info->name, sizeof(info->name));
|
||||
info->status = legacy_info->status;
|
||||
info->num_fences = num_fences;
|
||||
|
||||
pt = NULL;
|
||||
fence = sync_get_fence_info(info);
|
||||
while ((pt = sync_pt_info(legacy_info, pt)) != NULL) {
|
||||
strlcpy(fence->obj_name, pt->obj_name, sizeof(fence->obj_name));
|
||||
strlcpy(fence->driver_name, pt->driver_name,
|
||||
sizeof(fence->driver_name));
|
||||
fence->status = pt->status;
|
||||
fence->timestamp_ns = pt->timestamp_ns;
|
||||
fence++;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
struct sync_fence_info_data *sync_fence_info(int fd)
|
||||
{
|
||||
struct sync_fence_info_data *legacy_info;
|
||||
int uapi;
|
||||
|
||||
uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire);
|
||||
|
||||
if (uapi == UAPI_LEGACY || uapi == UAPI_UNKNOWN) {
|
||||
legacy_info = legacy_sync_fence_info(fd);
|
||||
if (legacy_info || errno != ENOTTY) {
|
||||
if (legacy_info && uapi == UAPI_UNKNOWN) {
|
||||
atomic_store_explicit(&g_uapi_version, UAPI_LEGACY,
|
||||
memory_order_release);
|
||||
}
|
||||
return legacy_info;
|
||||
}
|
||||
}
|
||||
|
||||
struct sync_file_info* file_info;
|
||||
file_info = modern_sync_file_info(fd);
|
||||
if (!file_info)
|
||||
return NULL;
|
||||
if (uapi == UAPI_UNKNOWN) {
|
||||
atomic_store_explicit(&g_uapi_version, UAPI_MODERN,
|
||||
memory_order_release);
|
||||
}
|
||||
legacy_info = sync_file_info_to_legacy_fence_info(file_info);
|
||||
sync_file_info_free(file_info);
|
||||
return legacy_info;
|
||||
}
|
||||
|
||||
struct sync_file_info* sync_file_info(int32_t fd)
|
||||
{
|
||||
struct sync_file_info *info;
|
||||
int uapi;
|
||||
|
||||
uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire);
|
||||
|
||||
if (uapi == UAPI_MODERN || uapi == UAPI_UNKNOWN) {
|
||||
info = modern_sync_file_info(fd);
|
||||
if (info || errno != ENOTTY) {
|
||||
if (info && uapi == UAPI_UNKNOWN) {
|
||||
atomic_store_explicit(&g_uapi_version, UAPI_MODERN,
|
||||
memory_order_release);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
struct sync_fence_info_data *legacy_info;
|
||||
legacy_info = legacy_sync_fence_info(fd);
|
||||
if (!legacy_info)
|
||||
return NULL;
|
||||
if (uapi == UAPI_UNKNOWN) {
|
||||
atomic_store_explicit(&g_uapi_version, UAPI_LEGACY,
|
||||
memory_order_release);
|
||||
}
|
||||
info = legacy_fence_info_to_sync_file_info(legacy_info);
|
||||
sync_fence_info_free(legacy_info);
|
||||
return info;
|
||||
}
|
||||
|
||||
struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info,
|
||||
struct sync_pt_info *itr)
|
||||
{
|
||||
if (itr == NULL)
|
||||
itr = (struct sync_pt_info *) info->pt_info;
|
||||
else
|
||||
itr = (struct sync_pt_info *) ((__u8 *)itr + itr->len);
|
||||
|
||||
if ((__u8 *)itr - (__u8 *)info >= (int)info->len)
|
||||
return NULL;
|
||||
|
||||
return itr;
|
||||
}
|
||||
|
||||
void sync_fence_info_free(struct sync_fence_info_data *info)
|
||||
{
|
||||
free(info);
|
||||
}
|
||||
|
||||
void sync_file_info_free(struct sync_file_info *info)
|
||||
{
|
||||
free(info);
|
||||
}
|
||||
|
||||
|
||||
int sw_sync_timeline_create(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = open("/sys/kernel/debug/sync/sw_sync", O_RDWR);
|
||||
if (ret < 0)
|
||||
ret = open("/dev/sw_sync", O_RDWR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sw_sync_timeline_inc(int fd, unsigned count)
|
||||
{
|
||||
__u32 arg = count;
|
||||
|
||||
return ioctl(fd, SW_SYNC_IOC_INC, &arg);
|
||||
}
|
||||
|
||||
int sw_sync_fence_create(int fd, const char *name, unsigned value)
|
||||
{
|
||||
struct sw_sync_create_fence_data data;
|
||||
int err;
|
||||
|
||||
data.value = value;
|
||||
strlcpy(data.name, name, sizeof(data.name));
|
||||
|
||||
err = ioctl(fd, SW_SYNC_IOC_CREATE_FENCE, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return data.fence;
|
||||
}
|
147
android/system/core/libsync/sync_test.c
Normal file
147
android/system/core/libsync/sync_test.c
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* sync_test.c
|
||||
*
|
||||
* Copyright 2012 Google, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android/sync.h>
|
||||
#include "sw_sync.h"
|
||||
|
||||
pthread_mutex_t printf_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
struct sync_thread_data {
|
||||
int thread_no;
|
||||
int fd[2];
|
||||
};
|
||||
|
||||
void *sync_thread(void *data)
|
||||
{
|
||||
struct sync_thread_data *sync_data = data;
|
||||
struct sync_fence_info_data *info;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
err = sync_wait(sync_data->fd[i], 10000);
|
||||
|
||||
pthread_mutex_lock(&printf_mutex);
|
||||
if (err < 0) {
|
||||
printf("thread %d wait %d failed: %s\n", sync_data->thread_no,
|
||||
i, strerror(errno));
|
||||
} else {
|
||||
printf("thread %d wait %d done\n", sync_data->thread_no, i);
|
||||
}
|
||||
info = sync_fence_info(sync_data->fd[i]);
|
||||
if (info) {
|
||||
struct sync_pt_info *pt_info = NULL;
|
||||
printf(" fence %s %d\n", info->name, info->status);
|
||||
|
||||
while ((pt_info = sync_pt_info(info, pt_info))) {
|
||||
int ts_sec = pt_info->timestamp_ns / 1000000000LL;
|
||||
int ts_usec = (pt_info->timestamp_ns % 1000000000LL) / 1000LL;
|
||||
printf(" pt %s %s %d %d.%06d", pt_info->obj_name,
|
||||
pt_info->driver_name, pt_info->status,
|
||||
ts_sec, ts_usec);
|
||||
if (!strcmp(pt_info->driver_name, "sw_sync"))
|
||||
printf(" val=%d\n", *(uint32_t *)pt_info->driver_data);
|
||||
else
|
||||
printf("\n");
|
||||
}
|
||||
sync_fence_info_free(info);
|
||||
}
|
||||
pthread_mutex_unlock(&printf_mutex);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
|
||||
{
|
||||
struct sync_thread_data sync_data[4];
|
||||
pthread_t threads[4];
|
||||
int sync_timeline_fd;
|
||||
int i, j;
|
||||
char str[256];
|
||||
|
||||
sync_timeline_fd = sw_sync_timeline_create();
|
||||
if (sync_timeline_fd < 0) {
|
||||
perror("can't create sw_sync_timeline:");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
sync_data[i].thread_no = i;
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
unsigned val = i + j * 3 + 1;
|
||||
snprintf(str, sizeof(str), "test_fence%d-%d", i, j);
|
||||
int fd = sw_sync_fence_create(sync_timeline_fd, str, val);
|
||||
if (fd < 0) {
|
||||
printf("can't create sync pt %d: %s", val, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
sync_data[i].fd[j] = fd;
|
||||
printf("sync_data[%d].fd[%d] = %d;\n", i, j, fd);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
sync_data[3].thread_no = 3;
|
||||
for (j = 0; j < 2; j++) {
|
||||
snprintf(str, sizeof(str), "merged_fence%d", j);
|
||||
sync_data[3].fd[j] = sync_merge(str, sync_data[0].fd[j], sync_data[1].fd[j]);
|
||||
if (sync_data[3].fd[j] < 0) {
|
||||
printf("can't merge sync pts %d and %d: %s\n",
|
||||
sync_data[0].fd[j], sync_data[1].fd[j], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
pthread_create(&threads[i], NULL, sync_thread, &sync_data[i]);
|
||||
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
int err;
|
||||
printf("press enter to inc to %d\n", i+1);
|
||||
fgets(str, sizeof(str), stdin);
|
||||
err = sw_sync_timeline_inc(sync_timeline_fd, 1);
|
||||
if (err < 0) {
|
||||
perror("can't increment sync obj:");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
printf("press enter to close sync_timeline\n");
|
||||
fgets(str, sizeof(str), stdin);
|
||||
|
||||
close(sync_timeline_fd);
|
||||
|
||||
printf("press enter to end test\n");
|
||||
fgets(str, sizeof(str), stdin);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
void *val;
|
||||
pthread_join(threads[i], &val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
626
android/system/core/libsync/tests/sync_test.cpp
Normal file
626
android/system/core/libsync/tests/sync_test.cpp
Normal file
|
@ -0,0 +1,626 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <android/sync.h>
|
||||
#include <sw_sync.h>
|
||||
#include <fcntl.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include <thread>
|
||||
#include <poll.h>
|
||||
#include <mutex>
|
||||
#include <algorithm>
|
||||
#include <tuple>
|
||||
#include <random>
|
||||
#include <unordered_map>
|
||||
|
||||
// TODO: better stress tests?
|
||||
// Handle more than 64 fd's simultaneously, i.e. fix sync_fence_info's 4k limit.
|
||||
// Handle wraparound in timelines like nvidia.
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
// C++ wrapper class for sync timeline.
|
||||
class SyncTimeline {
|
||||
int m_fd = -1;
|
||||
bool m_fdInitialized = false;
|
||||
public:
|
||||
SyncTimeline(const SyncTimeline &) = delete;
|
||||
SyncTimeline& operator=(SyncTimeline&) = delete;
|
||||
SyncTimeline() noexcept {
|
||||
int fd = sw_sync_timeline_create();
|
||||
if (fd == -1)
|
||||
return;
|
||||
m_fdInitialized = true;
|
||||
m_fd = fd;
|
||||
}
|
||||
void destroy() {
|
||||
if (m_fdInitialized) {
|
||||
close(m_fd);
|
||||
m_fd = -1;
|
||||
m_fdInitialized = false;
|
||||
}
|
||||
}
|
||||
~SyncTimeline() {
|
||||
destroy();
|
||||
}
|
||||
bool isValid() const {
|
||||
if (m_fdInitialized) {
|
||||
int status = fcntl(m_fd, F_GETFD, 0);
|
||||
if (status >= 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int getFd() const {
|
||||
return m_fd;
|
||||
}
|
||||
int inc(int val = 1) {
|
||||
return sw_sync_timeline_inc(m_fd, val);
|
||||
}
|
||||
};
|
||||
|
||||
struct SyncPointInfo {
|
||||
std::string driverName;
|
||||
std::string objectName;
|
||||
uint64_t timeStampNs;
|
||||
int status; // 1 sig, 0 active, neg is err
|
||||
};
|
||||
|
||||
// Wrapper class for sync fence.
|
||||
class SyncFence {
|
||||
int m_fd = -1;
|
||||
bool m_fdInitialized = false;
|
||||
static int s_fenceCount;
|
||||
|
||||
void setFd(int fd) {
|
||||
m_fd = fd;
|
||||
m_fdInitialized = true;
|
||||
}
|
||||
void clearFd() {
|
||||
m_fd = -1;
|
||||
m_fdInitialized = false;
|
||||
}
|
||||
public:
|
||||
bool isValid() const {
|
||||
if (m_fdInitialized) {
|
||||
int status = fcntl(m_fd, F_GETFD, 0);
|
||||
if (status >= 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
SyncFence& operator=(SyncFence &&rhs) noexcept {
|
||||
destroy();
|
||||
if (rhs.isValid()) {
|
||||
setFd(rhs.getFd());
|
||||
rhs.clearFd();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
SyncFence(SyncFence &&fence) noexcept {
|
||||
if (fence.isValid()) {
|
||||
setFd(fence.getFd());
|
||||
fence.clearFd();
|
||||
}
|
||||
}
|
||||
SyncFence(const SyncFence &fence) noexcept {
|
||||
// This is ok, as sync fences are immutable after construction, so a dup
|
||||
// is basically the same thing as a copy.
|
||||
if (fence.isValid()) {
|
||||
int fd = dup(fence.getFd());
|
||||
if (fd == -1)
|
||||
return;
|
||||
setFd(fd);
|
||||
}
|
||||
}
|
||||
SyncFence(const SyncTimeline &timeline,
|
||||
int value,
|
||||
const char *name = nullptr) noexcept {
|
||||
std::string autoName = "allocFence";
|
||||
autoName += s_fenceCount;
|
||||
s_fenceCount++;
|
||||
int fd = sw_sync_fence_create(timeline.getFd(), name ? name : autoName.c_str(), value);
|
||||
if (fd == -1)
|
||||
return;
|
||||
setFd(fd);
|
||||
}
|
||||
SyncFence(const SyncFence &a, const SyncFence &b, const char *name = nullptr) noexcept {
|
||||
std::string autoName = "mergeFence";
|
||||
autoName += s_fenceCount;
|
||||
s_fenceCount++;
|
||||
int fd = sync_merge(name ? name : autoName.c_str(), a.getFd(), b.getFd());
|
||||
if (fd == -1)
|
||||
return;
|
||||
setFd(fd);
|
||||
}
|
||||
SyncFence(const vector<SyncFence> &sources) noexcept {
|
||||
assert(sources.size());
|
||||
SyncFence temp(*begin(sources));
|
||||
for (auto itr = ++begin(sources); itr != end(sources); ++itr) {
|
||||
temp = SyncFence(*itr, temp);
|
||||
}
|
||||
if (temp.isValid()) {
|
||||
setFd(temp.getFd());
|
||||
temp.clearFd();
|
||||
}
|
||||
}
|
||||
void destroy() {
|
||||
if (isValid()) {
|
||||
close(m_fd);
|
||||
clearFd();
|
||||
}
|
||||
}
|
||||
~SyncFence() {
|
||||
destroy();
|
||||
}
|
||||
int getFd() const {
|
||||
return m_fd;
|
||||
}
|
||||
int wait(int timeout = -1) {
|
||||
return sync_wait(m_fd, timeout);
|
||||
}
|
||||
vector<SyncPointInfo> getInfo() const {
|
||||
vector<SyncPointInfo> fenceInfo;
|
||||
struct sync_file_info *info = sync_file_info(getFd());
|
||||
if (!info) {
|
||||
return fenceInfo;
|
||||
}
|
||||
const auto fences = sync_get_fence_info(info);
|
||||
for (uint32_t i = 0; i < info->num_fences; i++) {
|
||||
fenceInfo.push_back(SyncPointInfo{
|
||||
fences[i].driver_name,
|
||||
fences[i].obj_name,
|
||||
fences[i].timestamp_ns,
|
||||
fences[i].status});
|
||||
}
|
||||
sync_file_info_free(info);
|
||||
return fenceInfo;
|
||||
}
|
||||
int getSize() const {
|
||||
return getInfo().size();
|
||||
}
|
||||
int getSignaledCount() const {
|
||||
return countWithStatus(1);
|
||||
}
|
||||
int getActiveCount() const {
|
||||
return countWithStatus(0);
|
||||
}
|
||||
int getErrorCount() const {
|
||||
return countWithStatus(-1);
|
||||
}
|
||||
private:
|
||||
int countWithStatus(int status) const {
|
||||
int count = 0;
|
||||
for (auto &info : getInfo()) {
|
||||
if (info.status == status) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
static void CheckModernLegacyInfoMatch(const SyncFence& f) {
|
||||
struct sync_file_info* modern = sync_file_info(f.getFd());
|
||||
struct sync_fence_info_data* legacy = sync_fence_info(f.getFd());
|
||||
|
||||
ASSERT_TRUE(modern != NULL);
|
||||
ASSERT_TRUE(legacy != NULL);
|
||||
|
||||
EXPECT_STREQ(modern->name, legacy->name);
|
||||
EXPECT_EQ(modern->status, legacy->status);
|
||||
|
||||
uint32_t fenceIdx = 0;
|
||||
struct sync_pt_info* pt = sync_pt_info(legacy, NULL);
|
||||
const struct sync_fence_info* fences = sync_get_fence_info(modern);
|
||||
while (fenceIdx < modern->num_fences && pt != NULL) {
|
||||
EXPECT_STREQ(fences[fenceIdx].obj_name, pt->obj_name);
|
||||
EXPECT_STREQ(fences[fenceIdx].driver_name, pt->driver_name);
|
||||
EXPECT_EQ(fences[fenceIdx].status, pt->status);
|
||||
EXPECT_EQ(fences[fenceIdx].timestamp_ns, pt->timestamp_ns);
|
||||
|
||||
fenceIdx++;
|
||||
pt = sync_pt_info(legacy, pt);
|
||||
}
|
||||
EXPECT_EQ(fenceIdx, modern->num_fences);
|
||||
EXPECT_EQ(NULL, pt);
|
||||
}
|
||||
|
||||
int SyncFence::s_fenceCount = 0;
|
||||
|
||||
TEST(AllocTest, Timeline) {
|
||||
SyncTimeline timeline;
|
||||
ASSERT_TRUE(timeline.isValid());
|
||||
}
|
||||
|
||||
TEST(AllocTest, Fence) {
|
||||
SyncTimeline timeline;
|
||||
ASSERT_TRUE(timeline.isValid());
|
||||
|
||||
SyncFence fence(timeline, 1);
|
||||
ASSERT_TRUE(fence.isValid());
|
||||
CheckModernLegacyInfoMatch(fence);
|
||||
}
|
||||
|
||||
TEST(AllocTest, FenceNegative) {
|
||||
int timeline = sw_sync_timeline_create();
|
||||
ASSERT_GT(timeline, 0);
|
||||
|
||||
// bad fd.
|
||||
ASSERT_LT(sw_sync_fence_create(-1, "fence", 1), 0);
|
||||
|
||||
// No name - segfaults in user space.
|
||||
// Maybe we should be friendlier here?
|
||||
/*
|
||||
ASSERT_LT(sw_sync_fence_create(timeline, nullptr, 1), 0);
|
||||
*/
|
||||
close(timeline);
|
||||
}
|
||||
|
||||
TEST(FenceTest, OneTimelineWait) {
|
||||
SyncTimeline timeline;
|
||||
ASSERT_TRUE(timeline.isValid());
|
||||
|
||||
SyncFence fence(timeline, 5);
|
||||
ASSERT_TRUE(fence.isValid());
|
||||
|
||||
// Wait on fence until timeout.
|
||||
ASSERT_EQ(fence.wait(0), -1);
|
||||
ASSERT_EQ(errno, ETIME);
|
||||
|
||||
// Advance timeline from 0 -> 1
|
||||
ASSERT_EQ(timeline.inc(1), 0);
|
||||
|
||||
// Wait on fence until timeout.
|
||||
ASSERT_EQ(fence.wait(0), -1);
|
||||
ASSERT_EQ(errno, ETIME);
|
||||
|
||||
// Signal the fence.
|
||||
ASSERT_EQ(timeline.inc(4), 0);
|
||||
|
||||
// Wait successfully.
|
||||
ASSERT_EQ(fence.wait(0), 0);
|
||||
|
||||
// Go even futher, and confirm wait still succeeds.
|
||||
ASSERT_EQ(timeline.inc(10), 0);
|
||||
ASSERT_EQ(fence.wait(0), 0);
|
||||
}
|
||||
|
||||
TEST(FenceTest, OneTimelinePoll) {
|
||||
SyncTimeline timeline;
|
||||
ASSERT_TRUE(timeline.isValid());
|
||||
|
||||
SyncFence fence(timeline, 100);
|
||||
ASSERT_TRUE(fence.isValid());
|
||||
|
||||
fd_set set;
|
||||
FD_ZERO(&set);
|
||||
FD_SET(fence.getFd(), &set);
|
||||
|
||||
// Poll the fence, and wait till timeout.
|
||||
timeval time = {0};
|
||||
ASSERT_EQ(select(fence.getFd() + 1, &set, nullptr, nullptr, &time), 0);
|
||||
|
||||
// Advance the timeline.
|
||||
timeline.inc(100);
|
||||
timeline.inc(100);
|
||||
|
||||
// Select should return that the fd is read for reading.
|
||||
FD_ZERO(&set);
|
||||
FD_SET(fence.getFd(), &set);
|
||||
|
||||
ASSERT_EQ(select(fence.getFd() + 1, &set, nullptr, nullptr, &time), 1);
|
||||
ASSERT_TRUE(FD_ISSET(fence.getFd(), &set));
|
||||
}
|
||||
|
||||
TEST(FenceTest, OneTimelineMerge) {
|
||||
SyncTimeline timeline;
|
||||
ASSERT_TRUE(timeline.isValid());
|
||||
|
||||
// create fence a,b,c and then merge them all into fence d.
|
||||
SyncFence a(timeline, 1), b(timeline, 2), c(timeline, 3);
|
||||
ASSERT_TRUE(a.isValid());
|
||||
ASSERT_TRUE(b.isValid());
|
||||
ASSERT_TRUE(c.isValid());
|
||||
|
||||
SyncFence d({a,b,c});
|
||||
ASSERT_TRUE(d.isValid());
|
||||
|
||||
// confirm all fences have one active point (even d).
|
||||
ASSERT_EQ(a.getActiveCount(), 1);
|
||||
ASSERT_EQ(b.getActiveCount(), 1);
|
||||
ASSERT_EQ(c.getActiveCount(), 1);
|
||||
ASSERT_EQ(d.getActiveCount(), 1);
|
||||
|
||||
// confirm that d is not signaled until the max of a,b,c
|
||||
timeline.inc(1);
|
||||
ASSERT_EQ(a.getSignaledCount(), 1);
|
||||
ASSERT_EQ(d.getActiveCount(), 1);
|
||||
CheckModernLegacyInfoMatch(a);
|
||||
CheckModernLegacyInfoMatch(d);
|
||||
|
||||
timeline.inc(1);
|
||||
ASSERT_EQ(b.getSignaledCount(), 1);
|
||||
ASSERT_EQ(d.getActiveCount(), 1);
|
||||
CheckModernLegacyInfoMatch(b);
|
||||
CheckModernLegacyInfoMatch(d);
|
||||
|
||||
timeline.inc(1);
|
||||
ASSERT_EQ(c.getSignaledCount(), 1);
|
||||
ASSERT_EQ(d.getActiveCount(), 0);
|
||||
ASSERT_EQ(d.getSignaledCount(), 1);
|
||||
CheckModernLegacyInfoMatch(c);
|
||||
CheckModernLegacyInfoMatch(d);
|
||||
}
|
||||
|
||||
TEST(FenceTest, MergeSameFence) {
|
||||
SyncTimeline timeline;
|
||||
ASSERT_TRUE(timeline.isValid());
|
||||
|
||||
SyncFence fence(timeline, 5);
|
||||
ASSERT_TRUE(fence.isValid());
|
||||
|
||||
SyncFence selfMergeFence(fence, fence);
|
||||
ASSERT_TRUE(selfMergeFence.isValid());
|
||||
|
||||
ASSERT_EQ(selfMergeFence.getSignaledCount(), 0);
|
||||
CheckModernLegacyInfoMatch(selfMergeFence);
|
||||
|
||||
timeline.inc(5);
|
||||
ASSERT_EQ(selfMergeFence.getSignaledCount(), 1);
|
||||
CheckModernLegacyInfoMatch(selfMergeFence);
|
||||
}
|
||||
|
||||
TEST(FenceTest, PollOnDestroyedTimeline) {
|
||||
SyncTimeline timeline;
|
||||
ASSERT_TRUE(timeline.isValid());
|
||||
|
||||
SyncFence fenceSig(timeline, 100);
|
||||
SyncFence fenceKill(timeline, 200);
|
||||
|
||||
// Spawn a thread to wait on a fence when the timeline is killed.
|
||||
thread waitThread{
|
||||
[&]() {
|
||||
ASSERT_EQ(timeline.inc(100), 0);
|
||||
|
||||
// Wait on the fd.
|
||||
struct pollfd fds;
|
||||
fds.fd = fenceKill.getFd();
|
||||
fds.events = POLLIN | POLLERR;
|
||||
ASSERT_EQ(poll(&fds, 1, 0), 0);
|
||||
}
|
||||
};
|
||||
|
||||
// Wait for the thread to spool up.
|
||||
fenceSig.wait();
|
||||
|
||||
// Kill the timeline.
|
||||
timeline.destroy();
|
||||
|
||||
// wait for the thread to clean up.
|
||||
waitThread.join();
|
||||
}
|
||||
|
||||
TEST(FenceTest, MultiTimelineWait) {
|
||||
SyncTimeline timelineA, timelineB, timelineC;
|
||||
|
||||
SyncFence fenceA(timelineA, 5);
|
||||
SyncFence fenceB(timelineB, 5);
|
||||
SyncFence fenceC(timelineC, 5);
|
||||
|
||||
// Make a larger fence using 3 other fences from different timelines.
|
||||
SyncFence mergedFence({fenceA, fenceB, fenceC});
|
||||
ASSERT_TRUE(mergedFence.isValid());
|
||||
|
||||
// Confirm fence isn't signaled
|
||||
ASSERT_EQ(mergedFence.getActiveCount(), 3);
|
||||
ASSERT_EQ(mergedFence.wait(0), -1);
|
||||
ASSERT_EQ(errno, ETIME);
|
||||
|
||||
timelineA.inc(5);
|
||||
ASSERT_EQ(mergedFence.getActiveCount(), 2);
|
||||
ASSERT_EQ(mergedFence.getSignaledCount(), 1);
|
||||
CheckModernLegacyInfoMatch(mergedFence);
|
||||
|
||||
timelineB.inc(5);
|
||||
ASSERT_EQ(mergedFence.getActiveCount(), 1);
|
||||
ASSERT_EQ(mergedFence.getSignaledCount(), 2);
|
||||
CheckModernLegacyInfoMatch(mergedFence);
|
||||
|
||||
timelineC.inc(5);
|
||||
ASSERT_EQ(mergedFence.getActiveCount(), 0);
|
||||
ASSERT_EQ(mergedFence.getSignaledCount(), 3);
|
||||
CheckModernLegacyInfoMatch(mergedFence);
|
||||
|
||||
// confirm you can successfully wait.
|
||||
ASSERT_EQ(mergedFence.wait(100), 0);
|
||||
}
|
||||
|
||||
TEST(StressTest, TwoThreadsSharedTimeline) {
|
||||
const int iterations = 1 << 16;
|
||||
int counter = 0;
|
||||
SyncTimeline timeline;
|
||||
ASSERT_TRUE(timeline.isValid());
|
||||
|
||||
// Use a single timeline to synchronize two threads
|
||||
// hammmering on the same counter.
|
||||
auto threadMain = [&](int threadId) {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
SyncFence fence(timeline, i * 2 + threadId);
|
||||
ASSERT_TRUE(fence.isValid());
|
||||
|
||||
// Wait on the prior thread to complete.
|
||||
ASSERT_EQ(fence.wait(), 0);
|
||||
|
||||
// Confirm the previous thread's writes are visible and then inc.
|
||||
ASSERT_EQ(counter, i * 2 + threadId);
|
||||
counter++;
|
||||
|
||||
// Kick off the other thread.
|
||||
ASSERT_EQ(timeline.inc(), 0);
|
||||
}
|
||||
};
|
||||
|
||||
thread a{threadMain, 0};
|
||||
thread b{threadMain, 1};
|
||||
a.join();
|
||||
b.join();
|
||||
|
||||
// make sure the threads did not trample on one another.
|
||||
ASSERT_EQ(counter, iterations * 2);
|
||||
}
|
||||
|
||||
class ConsumerStressTest : public ::testing::TestWithParam<int> {};
|
||||
|
||||
TEST_P(ConsumerStressTest, MultiProducerSingleConsumer) {
|
||||
mutex lock;
|
||||
int counter = 0;
|
||||
int iterations = 1 << 12;
|
||||
|
||||
vector<SyncTimeline> producerTimelines(GetParam());
|
||||
vector<thread> threads;
|
||||
SyncTimeline consumerTimeline;
|
||||
|
||||
// Producer threads run this lambda.
|
||||
auto threadMain = [&](int threadId) {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
SyncFence fence(consumerTimeline, i);
|
||||
ASSERT_TRUE(fence.isValid());
|
||||
|
||||
// Wait for the consumer to finish. Use alternate
|
||||
// means of waiting on the fence.
|
||||
if ((iterations + threadId) % 8 != 0) {
|
||||
ASSERT_EQ(fence.wait(), 0);
|
||||
}
|
||||
else {
|
||||
while (fence.getSignaledCount() != 1) {
|
||||
ASSERT_EQ(fence.getErrorCount(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Every producer increments the counter, the consumer checks + erases it.
|
||||
lock.lock();
|
||||
counter++;
|
||||
lock.unlock();
|
||||
|
||||
ASSERT_EQ(producerTimelines[threadId].inc(), 0);
|
||||
}
|
||||
};
|
||||
|
||||
for (int i = 0; i < GetParam(); i++) {
|
||||
threads.push_back(thread{threadMain, i});
|
||||
}
|
||||
|
||||
// Consumer thread runs this loop.
|
||||
for (int i = 1; i <= iterations; i++) {
|
||||
// Create a fence representing all producers final timelines.
|
||||
vector<SyncFence> fences;
|
||||
for (auto& timeline : producerTimelines) {
|
||||
fences.push_back(SyncFence(timeline, i));
|
||||
}
|
||||
SyncFence mergeFence(fences);
|
||||
ASSERT_TRUE(mergeFence.isValid());
|
||||
|
||||
// Make sure we see an increment from every producer thread. Vary
|
||||
// the means by which we wait.
|
||||
if (iterations % 8 != 0) {
|
||||
ASSERT_EQ(mergeFence.wait(), 0);
|
||||
}
|
||||
else {
|
||||
while (mergeFence.getSignaledCount() != mergeFence.getSize()) {
|
||||
ASSERT_EQ(mergeFence.getErrorCount(), 0);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(counter, GetParam()*i);
|
||||
|
||||
// Release the producer threads.
|
||||
ASSERT_EQ(consumerTimeline.inc(), 0);
|
||||
}
|
||||
|
||||
for_each(begin(threads), end(threads), [](thread& thread) { thread.join(); });
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
ParameterizedStressTest,
|
||||
ConsumerStressTest,
|
||||
::testing::Values(2,4,16));
|
||||
|
||||
class MergeStressTest : public ::testing::TestWithParam<tuple<int, int>> {};
|
||||
|
||||
template <typename K, typename V> using dict = unordered_map<K,V>;
|
||||
|
||||
TEST_P(MergeStressTest, RandomMerge) {
|
||||
int timelineCount = get<0>(GetParam());
|
||||
int mergeCount = get<1>(GetParam());
|
||||
|
||||
vector<SyncTimeline> timelines(timelineCount);
|
||||
|
||||
default_random_engine generator;
|
||||
uniform_int_distribution<int> timelineDist(0, timelines.size()-1);
|
||||
uniform_int_distribution<int> syncPointDist(0, numeric_limits<int>::max());
|
||||
|
||||
SyncFence fence(timelines[0], 0);
|
||||
ASSERT_TRUE(fence.isValid());
|
||||
|
||||
unordered_map<int, int> fenceMap;
|
||||
fenceMap.insert(make_pair(0, 0));
|
||||
|
||||
// Randomly create syncpoints out of a fixed set of timelines, and merge them together.
|
||||
for (int i = 0; i < mergeCount; i++) {
|
||||
|
||||
// Generate syncpoint.
|
||||
int timelineOffset = timelineDist(generator);
|
||||
const SyncTimeline& timeline = timelines[timelineOffset];
|
||||
int syncPoint = syncPointDist(generator);
|
||||
|
||||
// Keep track of the latest syncpoint in each timeline.
|
||||
auto itr = fenceMap.find(timelineOffset);
|
||||
if (itr == end(fenceMap)) {
|
||||
fenceMap.insert(make_pair(timelineOffset, syncPoint));
|
||||
}
|
||||
else {
|
||||
int oldSyncPoint = itr->second;
|
||||
fenceMap.erase(itr);
|
||||
fenceMap.insert(make_pair(timelineOffset, max(syncPoint, oldSyncPoint)));
|
||||
}
|
||||
|
||||
// Merge.
|
||||
fence = SyncFence(fence, SyncFence(timeline, syncPoint));
|
||||
ASSERT_TRUE(fence.isValid());
|
||||
CheckModernLegacyInfoMatch(fence);
|
||||
}
|
||||
|
||||
// Confirm our map matches the fence.
|
||||
ASSERT_EQ(fence.getSize(), fenceMap.size());
|
||||
|
||||
// Trigger the merged fence.
|
||||
for (auto& item: fenceMap) {
|
||||
ASSERT_EQ(fence.wait(0), -1);
|
||||
ASSERT_EQ(errno, ETIME);
|
||||
|
||||
// Increment the timeline to the last syncpoint.
|
||||
timelines[item.first].inc(item.second);
|
||||
}
|
||||
|
||||
// Check that the fence is triggered.
|
||||
ASSERT_EQ(fence.wait(0), 0);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
ParameterizedMergeStressTest,
|
||||
MergeStressTest,
|
||||
::testing::Combine(::testing::Values(16,32), ::testing::Values(32, 1024, 1024*32)));
|
||||
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue