Merge 658804a522 into 84816e064a
This commit is contained in:
commit
cc6ad7ebec
@ -167,6 +167,27 @@ list(APPEND uv_cflags ${lint-utf8-msvc} )
|
||||
check_c_compiler_flag(-fno-strict-aliasing UV_F_STRICT_ALIASING)
|
||||
list(APPEND uv_cflags $<$<BOOL:${UV_F_STRICT_ALIASING}>:-fno-strict-aliasing>)
|
||||
|
||||
# Thread safety analysis - only enabled for Clang
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
check_c_compiler_flag(-Wthread-safety UV_THREAD_SAFETY)
|
||||
check_c_compiler_flag(-Wthread-safety-negative UV_THREAD_SAFETY_NEGATIVE)
|
||||
check_c_compiler_flag(-Wthread-safety-beta UV_THREAD_SAFETY_BETA)
|
||||
check_c_compiler_flag(-Wthread-safety-pointer UV_THREAD_SAFETY_POINTER)
|
||||
|
||||
if(UV_THREAD_SAFETY)
|
||||
list(APPEND uv_cflags -Wthread-safety)
|
||||
endif()
|
||||
if(UV_THREAD_SAFETY_NEGATIVE)
|
||||
list(APPEND uv_cflags -Wthread-safety-negative)
|
||||
endif()
|
||||
if(UV_THREAD_SAFETY_BETA)
|
||||
list(APPEND uv_cflags -Wthread-safety-beta)
|
||||
endif()
|
||||
if(UV_THREAD_SAFETY_POINTER)
|
||||
list(APPEND uv_cflags -Wthread-safety-pointer)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
# Error on calling undeclared functions.
|
||||
list(APPEND uv_cflags "/we4013")
|
||||
|
||||
@ -39,6 +39,11 @@ CC_CHECK_CFLAGS_APPEND([-Wextra])
|
||||
CC_CHECK_CFLAGS_APPEND([-Wno-long-long])
|
||||
CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter])
|
||||
CC_CHECK_CFLAGS_APPEND([-Wstrict-prototypes])
|
||||
# Thread safety analysis warnings (Clang only)
|
||||
CC_CHECK_CFLAGS_APPEND([-Wthread-safety])
|
||||
CC_CHECK_CFLAGS_APPEND([-Wthread-safety-negative])
|
||||
CC_CHECK_CFLAGS_APPEND([-Wthread-safety-beta])
|
||||
CC_CHECK_CFLAGS_APPEND([-Wthread-safety-pointer])
|
||||
# AM_PROG_AR is not available in automake v0.11 but it's essential in v0.12.
|
||||
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
||||
# autoconf complains if AC_PROG_LIBTOOL precedes AM_PROG_AR.
|
||||
|
||||
@ -167,8 +167,8 @@ Threads
|
||||
If the function fails, the return value is less than zero.
|
||||
Sets the scheduling priority of the thread specified by tid. It requires elevated
|
||||
privilege to set specific priorities on some platforms.
|
||||
The priority can be set to the following constants. UV_THREAD_PRIORITY_HIGHEST,
|
||||
UV_THREAD_PRIORITY_ABOVE_NORMAL, UV_THREAD_PRIORITY_NORMAL,
|
||||
The priority can be set to the following constants. UV_THREAD_PRIORITY_HIGHEST,
|
||||
UV_THREAD_PRIORITY_ABOVE_NORMAL, UV_THREAD_PRIORITY_NORMAL,
|
||||
UV_THREAD_PRIORITY_BELOW_NORMAL, UV_THREAD_PRIORITY_LOWEST.
|
||||
|
||||
.. c:function:: int uv_thread_getpriority(uv_thread_t tid, int* priority)
|
||||
@ -282,3 +282,81 @@ return type is void, of course).
|
||||
.. c:function:: int uv_barrier_init(uv_barrier_t* barrier, unsigned int count)
|
||||
.. c:function:: void uv_barrier_destroy(uv_barrier_t* barrier)
|
||||
.. c:function:: int uv_barrier_wait(uv_barrier_t* barrier)
|
||||
|
||||
Thread Safety Analysis Helpers
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
These functions provide support for Clang's thread safety analysis when enabled.
|
||||
They are no-op inline functions that exist solely to communicate lock state
|
||||
information to the static analyzer. They have no runtime functionality and are
|
||||
compiled away in release builds. For the purposes of this analysis, `uv_mutex_t`
|
||||
is assumed not to be used with `uv_mutex_init_recursive`.
|
||||
|
||||
.. note::
|
||||
These functions are only useful when compiling with Clang and thread safety
|
||||
analysis enabled (``-Wthread-safety``). They have no effect with other
|
||||
compilers or when thread safety analysis warnings are disabled.
|
||||
|
||||
**Mutex Helpers:**
|
||||
|
||||
.. c:function:: void uv_mutex_assume_locked(uv_mutex_t* handle)
|
||||
|
||||
Tells the thread safety analyzer to assume that the mutex is currently held
|
||||
by the calling thread. Use this when a mutex is acquired when the lock state
|
||||
is established through external means that the analyzer cannot track, such
|
||||
as conditional logic.
|
||||
|
||||
.. c:function:: void uv_mutex_assume_unlocked(uv_mutex_t* handle)
|
||||
|
||||
Tells the thread safety analyzer to assume that the mutex it thought was
|
||||
held is no longer held by the calling thread, releases capability tracking
|
||||
for it. Use this when a mutex is released through external means that the
|
||||
analyzer could not currently analyze adequately (such as a callback).
|
||||
|
||||
.. c:function:: void uv_mutex_assert_unlocked(uv_mutex_t* handle)
|
||||
|
||||
Asserts to the thread safety analyzer that the mutex must not be held when
|
||||
this function is called. Use this to document and verify that certain code
|
||||
paths require a mutex to be unlocked. This is a path-aware version of
|
||||
annotating the whole function with UV_EXCLUDES.
|
||||
|
||||
**Read-Write Lock Helpers:**
|
||||
|
||||
.. c:function:: void uv_rwlock_assume_rdlocked(uv_rwlock_t* handle)
|
||||
|
||||
Tells the thread safety analyzer to assume that the read-write lock is
|
||||
currently held for reading by the calling thread.
|
||||
|
||||
.. c:function:: void uv_rwlock_assume_wrlocked(uv_rwlock_t* handle)
|
||||
|
||||
Tells the thread safety analyzer to assume that the read-write lock is
|
||||
currently held for writing by the calling thread.
|
||||
|
||||
.. c:function:: void uv_rwlock_assume_rdunlocked(uv_rwlock_t* handle)
|
||||
|
||||
Tells the thread safety analyzer to assume that the read-write lock is
|
||||
released for reading by the calling thread.
|
||||
|
||||
.. c:function:: void uv_rwlock_assume_wrunlocked(uv_rwlock_t* handle)
|
||||
|
||||
Tells the thread safety analyzer to assume that the read-write lock is
|
||||
released for writing by the calling thread.
|
||||
|
||||
.. c:function:: void uv_rwlock_assert_unlocked(uv_rwlock_t* handle)
|
||||
|
||||
Asserts to the thread safety analyzer that the read-write lock must not be
|
||||
held (for reading or writing) when this function is called.
|
||||
|
||||
**Once Helpers:**
|
||||
|
||||
.. c:function:: void uv_once_assume_ran(uv_once_t* handle)
|
||||
|
||||
Tell the thread safety analyzer to assume that :c:func:`uv_once` has already
|
||||
been called for the given ``handle`` and the initialization callback has completed.
|
||||
|
||||
This function is used in scenarios where the analyzer cannot determine that
|
||||
the once-initialization has already occurred through other means (such as when
|
||||
the initialization happens in a different compilation unit or through
|
||||
external guarantees). It also can be called to entirely bypass running the
|
||||
`once` function while still satisfying the analyzer, for example, if known
|
||||
to be guaranteed to be single-threaded at the time of initialization.
|
||||
|
||||
226
include/uv.h
226
include/uv.h
@ -58,6 +58,174 @@ extern "C" {
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Clang thread safety analysis annotations */
|
||||
#if defined(__clang__)
|
||||
# define UV__THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
|
||||
#else
|
||||
# define UV__THREAD_ANNOTATION_ATTRIBUTE__(x) /* no-op */
|
||||
#endif
|
||||
|
||||
#define UV_CAPABILITY(x) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
|
||||
|
||||
#define UV_ACQUIRE(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_RELEASE(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_TRY_ACQUIRE(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_REQUIRES(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_RELOCKS(...) \
|
||||
UV_REQUIRES(__VA_ARGS__) UV_RELEASE(__VA_ARGS__) UV_ACQUIRE(__VA_ARGS__);
|
||||
|
||||
/* Macro trickery needed to negate each __VA_ARGS__ argument (up to 5). */
|
||||
#define UV__NEGATE_ARGS_1(a) !a
|
||||
#define UV__NEGATE_ARGS_2(a, b) !a, !b
|
||||
#define UV__NEGATE_ARGS_3(a, b, c) !a, !b, !c
|
||||
#define UV__NEGATE_ARGS_4(a, b, c, d) !a, !b, !c, !d
|
||||
#define UV__NEGATE_ARGS_5(a, b, c, d, e) !a, !b, !c, !d, !e
|
||||
#define UV__COUNT_ARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N
|
||||
#define UV__COUNT_ARGS(...) UV__COUNT_ARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
|
||||
#define UV__NEGATE_DISPATCH(N) UV__NEGATE_ARGS_##N
|
||||
#define UV__NEGATE_ARGS_APPLY(N, ...) UV__NEGATE_DISPATCH(N)(__VA_ARGS__)
|
||||
#define UV__NEGATE_ALL_ARGS(...) UV__NEGATE_ARGS_APPLY(UV__COUNT_ARGS(__VA_ARGS__), __VA_ARGS__)
|
||||
|
||||
/* UV_EXCLUDES is intentionally mapped to requires_capability(!x) instead of
|
||||
* locks_excluded(x) because negative capabilities are more precise and integrate
|
||||
* better with the capability analysis system. While locks_excluded is an older
|
||||
* annotation that simply checks a lock isn't held, requires_capability(!x)
|
||||
* participates in the full capability analysis, allowing for better
|
||||
* composability and more accurate tracking of lock states. */
|
||||
#define UV_EXCLUDES(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(UV__NEGATE_ALL_ARGS(__VA_ARGS__)))
|
||||
|
||||
#define UV_ACQUIRE_SHARED(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_RELEASE_SHARED(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_TRY_ACQUIRE_SHARED(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_REQUIRES_SHARED(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
|
||||
|
||||
/* Data annotations - specify which locks protect which data members */
|
||||
#define UV_GUARDED_BY(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(__VA_ARGS__))
|
||||
|
||||
#define UV_PT_GUARDED_BY(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(__VA_ARGS__))
|
||||
|
||||
/* Lock ordering annotations - prevent deadlock by specifying acquisition order */
|
||||
#define UV_ACQUIRED_BEFORE(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
|
||||
|
||||
#define UV_ACQUIRED_AFTER(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
|
||||
|
||||
/* Use this assert where it is not possible to use UV_REQUIRES, such as at the
|
||||
* start of a callback. */
|
||||
#define UV_ASSERT_CAPABILITY(x) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
|
||||
|
||||
#define UV_ASSERT_SHARED_CAPABILITY(x) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
|
||||
|
||||
/* Disable analysis for specific functions. */
|
||||
#define UV_NO_THREAD_SAFETY_ANALYSIS \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
|
||||
|
||||
/* Clang thread safety analysis annotations */
|
||||
#if defined(__clang__)
|
||||
# define UV__THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
|
||||
#else
|
||||
# define UV__THREAD_ANNOTATION_ATTRIBUTE__(x) /* no-op */
|
||||
#endif
|
||||
|
||||
#define UV_CAPABILITY(x) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
|
||||
|
||||
#define UV_ACQUIRE(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_RELEASE(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_TRY_ACQUIRE(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_REQUIRES(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_RELOCKS(...) \
|
||||
UV_REQUIRES(__VA_ARGS__) UV_RELEASE(__VA_ARGS__) UV_ACQUIRE(__VA_ARGS__);
|
||||
|
||||
/* Macro trickery needed to negate each __VA_ARGS__ argument (up to 5). */
|
||||
#define UV__NEGATE_ARGS_1(a) !a
|
||||
#define UV__NEGATE_ARGS_2(a, b) !a, !b
|
||||
#define UV__NEGATE_ARGS_3(a, b, c) !a, !b, !c
|
||||
#define UV__NEGATE_ARGS_4(a, b, c, d) !a, !b, !c, !d
|
||||
#define UV__NEGATE_ARGS_5(a, b, c, d, e) !a, !b, !c, !d, !e
|
||||
#define UV__COUNT_ARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N
|
||||
#define UV__COUNT_ARGS(...) UV__COUNT_ARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
|
||||
#define UV__NEGATE_DISPATCH(N) UV__NEGATE_ARGS_##N
|
||||
#define UV__NEGATE_ARGS_APPLY(N, ...) UV__NEGATE_DISPATCH(N)(__VA_ARGS__)
|
||||
#define UV__NEGATE_ALL_ARGS(...) UV__NEGATE_ARGS_APPLY(UV__COUNT_ARGS(__VA_ARGS__), __VA_ARGS__)
|
||||
|
||||
/* UV_EXCLUDES is intentionally mapped to requires_capability(!x) instead of
|
||||
* locks_excluded(x) because negative capabilities are more precise and integrate
|
||||
* better with the capability analysis system. While locks_excluded is an older
|
||||
* annotation that simply checks a lock isn't held, requires_capability(!x)
|
||||
* participates in the full capability analysis, allowing for better
|
||||
* composability and more accurate tracking of lock states. */
|
||||
#define UV_EXCLUDES(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(UV__NEGATE_ALL_ARGS(__VA_ARGS__)))
|
||||
|
||||
#define UV_ACQUIRE_SHARED(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_RELEASE_SHARED(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_TRY_ACQUIRE_SHARED(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define UV_REQUIRES_SHARED(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
|
||||
|
||||
/* Data annotations - specify which locks protect which data members */
|
||||
#define UV_GUARDED_BY(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(__VA_ARGS__))
|
||||
|
||||
#define UV_PT_GUARDED_BY(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(__VA_ARGS__))
|
||||
|
||||
/* Lock ordering annotations - prevent deadlock by specifying acquisition order */
|
||||
#define UV_ACQUIRED_BEFORE(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
|
||||
|
||||
#define UV_ACQUIRED_AFTER(...) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
|
||||
|
||||
/* Use this assert where it is not possible to use UV_REQUIRES, such as at the
|
||||
* start of a callback. */
|
||||
#define UV_ASSERT_CAPABILITY(x) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
|
||||
|
||||
#define UV_ASSERT_SHARED_CAPABILITY(x) \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
|
||||
|
||||
/* Disable analysis for specific functions. */
|
||||
#define UV_NO_THREAD_SAFETY_ANALYSIS \
|
||||
UV__THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
|
||||
|
||||
/* Internal type, do not use. */
|
||||
struct uv__queue {
|
||||
struct uv__queue* next;
|
||||
@ -510,6 +678,14 @@ UV_EXTERN int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd);
|
||||
|
||||
UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len);
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define INLINE __inline
|
||||
#elif defined(__GNUC__) || defined(__MVS__)
|
||||
# define INLINE __inline__
|
||||
#else
|
||||
# define INLINE inline
|
||||
#endif
|
||||
|
||||
UV_EXTERN int uv_pipe(uv_file fds[2], int read_flags, int write_flags);
|
||||
UV_EXTERN int uv_socketpair(int type,
|
||||
int protocol,
|
||||
@ -1845,21 +2021,38 @@ UV_EXTERN void uv_dlclose(uv_lib_t* lib);
|
||||
UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr);
|
||||
UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib);
|
||||
|
||||
|
||||
UV_EXTERN int uv_mutex_init(uv_mutex_t* handle);
|
||||
UV_EXTERN int uv_mutex_init_recursive(uv_mutex_t* handle);
|
||||
UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle);
|
||||
UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle);
|
||||
UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle);
|
||||
UV_EXTERN void uv_mutex_unlock(uv_mutex_t* handle);
|
||||
UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle) UV_ACQUIRE(handle);
|
||||
UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle) UV_TRY_ACQUIRE(0, handle);
|
||||
UV_EXTERN void uv_mutex_unlock(uv_mutex_t* handle) UV_RELEASE(handle);
|
||||
static INLINE void uv_mutex_assume_locked(uv_mutex_t* handle)
|
||||
UV_ASSERT_CAPABILITY(handle) {};
|
||||
static INLINE void uv_mutex_assume_unlocked(uv_mutex_t* handle)
|
||||
UV_RELEASE(handle) UV_NO_THREAD_SAFETY_ANALYSIS {};
|
||||
static INLINE void uv_mutex_assert_unlocked(uv_mutex_t* handle)
|
||||
UV_EXCLUDES(handle) {};
|
||||
|
||||
UV_EXTERN int uv_rwlock_init(uv_rwlock_t* rwlock);
|
||||
UV_EXTERN void uv_rwlock_destroy(uv_rwlock_t* rwlock);
|
||||
UV_EXTERN void uv_rwlock_rdlock(uv_rwlock_t* rwlock);
|
||||
UV_EXTERN int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock);
|
||||
UV_EXTERN void uv_rwlock_rdunlock(uv_rwlock_t* rwlock);
|
||||
UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock);
|
||||
UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock);
|
||||
UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock);
|
||||
UV_EXTERN void uv_rwlock_rdlock(uv_rwlock_t* rwlock) UV_ACQUIRE_SHARED(rwlock);
|
||||
UV_EXTERN int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) UV_TRY_ACQUIRE_SHARED(0, rwlock);
|
||||
UV_EXTERN void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) UV_RELEASE_SHARED(rwlock);
|
||||
UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock) UV_ACQUIRE(rwlock);
|
||||
UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) UV_TRY_ACQUIRE(0, rwlock);
|
||||
UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) UV_RELEASE(rwlock);
|
||||
static INLINE void uv_rwlock_assume_rdlocked(uv_rwlock_t* handle)
|
||||
UV_ASSERT_SHARED_CAPABILITY(handle) {};
|
||||
static INLINE void uv_rwlock_assume_wrlocked(uv_rwlock_t* handle)
|
||||
UV_ASSERT_CAPABILITY(handle) {};
|
||||
static INLINE void uv_rwlock_assume_rdunlocked(uv_rwlock_t* handle)
|
||||
UV_RELEASE_SHARED(handle) UV_NO_THREAD_SAFETY_ANALYSIS {};
|
||||
static INLINE void uv_rwlock_assume_wrunlocked(uv_rwlock_t* handle)
|
||||
UV_RELEASE(handle) UV_NO_THREAD_SAFETY_ANALYSIS {};
|
||||
static INLINE void uv_rwlock_assert_unlocked(uv_rwlock_t* handle)
|
||||
UV_EXCLUDES(handle) {};
|
||||
|
||||
UV_EXTERN int uv_sem_init(uv_sem_t* sem, unsigned int value);
|
||||
UV_EXTERN void uv_sem_destroy(uv_sem_t* sem);
|
||||
@ -1876,12 +2069,19 @@ UV_EXTERN int uv_barrier_init(uv_barrier_t* barrier, unsigned int count);
|
||||
UV_EXTERN void uv_barrier_destroy(uv_barrier_t* barrier);
|
||||
UV_EXTERN int uv_barrier_wait(uv_barrier_t* barrier);
|
||||
|
||||
UV_EXTERN void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex);
|
||||
UV_EXTERN void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) UV_RELOCKS(mutex);
|
||||
UV_EXTERN int uv_cond_timedwait(uv_cond_t* cond,
|
||||
uv_mutex_t* mutex,
|
||||
uint64_t timeout);
|
||||
uint64_t timeout) UV_RELOCKS(mutex);
|
||||
|
||||
UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void));
|
||||
/* Annotate this function for thread safety analysis purposes such that uv_once
|
||||
* can acquire the guard with UV_ACQUIRE internally for the callback to write any
|
||||
* values, then return with it in the SHARED state for the callee to read any
|
||||
* values it protects. */
|
||||
UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void))
|
||||
UV_EXCLUDES(guard) UV_ASSERT_SHARED_CAPABILITY(guard);
|
||||
static INLINE void uv_once_assume_ran(uv_once_t* handle)
|
||||
UV_ASSERT_SHARED_CAPABILITY(handle) UV_NO_THREAD_SAFETY_ANALYSIS {}
|
||||
|
||||
UV_EXTERN int uv_key_create(uv_key_t* key);
|
||||
UV_EXTERN void uv_key_delete(uv_key_t* key);
|
||||
@ -1988,6 +2188,8 @@ UV_EXTERN void uv_wtf8_to_utf16(const char* wtf8,
|
||||
#undef UV_SIGNAL_PRIVATE_FIELDS
|
||||
#undef UV_LOOP_PRIVATE_FIELDS
|
||||
#undef UV__ERR
|
||||
#undef INLINE
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -124,12 +124,18 @@ typedef int uv_os_sock_t;
|
||||
typedef int uv_os_fd_t;
|
||||
typedef pid_t uv_pid_t;
|
||||
|
||||
#define UV_ONCE_INIT PTHREAD_ONCE_INIT
|
||||
typedef struct UV_CAPABILITY("uv_once") uv_once_s {
|
||||
pthread_once_t o;
|
||||
} uv_once_t;
|
||||
|
||||
typedef pthread_once_t uv_once_t;
|
||||
#define UV_ONCE_INIT { PTHREAD_ONCE_INIT }
|
||||
typedef pthread_t uv_thread_t;
|
||||
typedef pthread_mutex_t uv_mutex_t;
|
||||
typedef pthread_rwlock_t uv_rwlock_t;
|
||||
typedef struct UV_CAPABILITY("uv_mutex") uv_mutex_s {
|
||||
pthread_mutex_t m;
|
||||
} uv_mutex_t;
|
||||
typedef struct UV_CAPABILITY("uv_rwlock") uv_rwlock_s {
|
||||
pthread_rwlock_t rw;
|
||||
} uv_rwlock_t;
|
||||
typedef UV_PLATFORM_SEM_T uv_sem_t;
|
||||
typedef pthread_cond_t uv_cond_t;
|
||||
typedef pthread_key_t uv_key_t;
|
||||
|
||||
@ -237,7 +237,9 @@ typedef HANDLE uv_thread_t;
|
||||
|
||||
typedef HANDLE uv_sem_t;
|
||||
|
||||
typedef CRITICAL_SECTION uv_mutex_t;
|
||||
typedef struct UV_CAPABILITY("uv_mutex") uv_mutex_s {
|
||||
CRITICAL_SECTION cs;
|
||||
} uv_mutex_t;
|
||||
|
||||
/* This condition variable implementation is based on the SetEvent solution
|
||||
* (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
|
||||
@ -256,7 +258,7 @@ typedef union {
|
||||
} unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */
|
||||
} uv_cond_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct UV_CAPABILITY("uv_rwlock") uv_rwlock_s {
|
||||
SRWLOCK read_write_lock_;
|
||||
/* TODO: retained for ABI compatibility; remove me in v2.x */
|
||||
#ifdef _WIN64
|
||||
@ -281,7 +283,7 @@ typedef struct {
|
||||
|
||||
#define UV_ONCE_INIT { 0, INIT_ONCE_STATIC_INIT }
|
||||
|
||||
typedef struct uv_once_s {
|
||||
typedef struct UV_CAPABILITY("uv_once") uv_once_s {
|
||||
unsigned char unused;
|
||||
INIT_ONCE init_once;
|
||||
} uv_once_t;
|
||||
|
||||
@ -54,7 +54,7 @@ static void uv__cancelled(struct uv__work* w) {
|
||||
/* To avoid deadlock with uv_cancel() it's crucial that the worker
|
||||
* never holds the global mutex and the loop-local mutex at the same time.
|
||||
*/
|
||||
static void worker(void* arg) {
|
||||
static void worker(void* arg) UV_EXCLUDES(&mutex) {
|
||||
struct uv__work* w;
|
||||
struct uv__queue* q;
|
||||
int is_slow_work;
|
||||
@ -140,7 +140,7 @@ static void worker(void* arg) {
|
||||
}
|
||||
|
||||
|
||||
static void post(struct uv__queue* q, enum uv__work_kind kind) {
|
||||
static void post(struct uv__queue* q, enum uv__work_kind kind) UV_EXCLUDES(&mutex) {
|
||||
uv_mutex_lock(&mutex);
|
||||
if (kind == UV__WORK_SLOW_IO) {
|
||||
/* Insert into a separate queue. */
|
||||
@ -165,7 +165,7 @@ static void post(struct uv__queue* q, enum uv__work_kind kind) {
|
||||
/* TODO(itodorov) - zos: revisit when Woz compiler is available. */
|
||||
__attribute__((destructor))
|
||||
#endif
|
||||
void uv__threadpool_cleanup(void) {
|
||||
void uv__threadpool_cleanup(void) UV_EXCLUDES(&mutex) {
|
||||
unsigned int i;
|
||||
|
||||
if (nthreads == 0)
|
||||
@ -277,7 +277,7 @@ void uv__work_submit(uv_loop_t* loop,
|
||||
struct uv__work* w,
|
||||
enum uv__work_kind kind,
|
||||
void (*work)(struct uv__work* w),
|
||||
void (*done)(struct uv__work* w, int status)) {
|
||||
void (*done)(struct uv__work* w, int status)) UV_EXCLUDES(&once, &mutex) {
|
||||
uv_once(&once, init_once);
|
||||
w->loop = loop;
|
||||
w->work = work;
|
||||
@ -289,7 +289,7 @@ void uv__work_submit(uv_loop_t* loop,
|
||||
/* TODO(bnoordhuis) teach libuv how to cancel file operations
|
||||
* that go through io_uring instead of the thread pool.
|
||||
*/
|
||||
static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
|
||||
static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) UV_EXCLUDES(&once, &mutex) {
|
||||
int cancelled;
|
||||
|
||||
uv_once(&once, init_once); /* Ensure |mutex| is initialized. */
|
||||
@ -379,7 +379,7 @@ static void uv__queue_done(struct uv__work* w, int err) {
|
||||
int uv_queue_work(uv_loop_t* loop,
|
||||
uv_work_t* req,
|
||||
uv_work_cb work_cb,
|
||||
uv_after_work_cb after_work_cb) {
|
||||
uv_after_work_cb after_work_cb) UV_EXCLUDES(&once, &mutex) {
|
||||
if (work_cb == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
@ -396,7 +396,7 @@ int uv_queue_work(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
|
||||
int uv_cancel(uv_req_t* req) {
|
||||
int uv_cancel(uv_req_t* req) UV_EXCLUDES(&once, &mutex) {
|
||||
struct uv__work* wreq;
|
||||
uv_loop_t* loop;
|
||||
|
||||
|
||||
@ -261,7 +261,11 @@ static void uv__async_send(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
static int uv__async_start(uv_loop_t* loop) {
|
||||
static int uv__async_start(uv_loop_t* loop)
|
||||
#if UV__KQUEUE_EVFILT_USER
|
||||
UV_EXCLUDES(&kqueue_runtime_detection_guard)
|
||||
#endif
|
||||
{
|
||||
int pipefd[2];
|
||||
int err;
|
||||
#if UV__KQUEUE_EVFILT_USER
|
||||
@ -369,7 +373,11 @@ void uv__async_stop(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
int uv__async_fork(uv_loop_t* loop) {
|
||||
int uv__async_fork(uv_loop_t* loop)
|
||||
#if UV__KQUEUE_EVFILT_USER
|
||||
UV_EXCLUDES(&kqueue_runtime_detection_guard)
|
||||
#endif
|
||||
{
|
||||
struct uv__queue queue;
|
||||
struct uv__queue* q;
|
||||
uv_async_t* h;
|
||||
|
||||
@ -57,7 +57,7 @@ static void uv__hrtime_init_once(void) {
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) UV_EXCLUDES(&once) {
|
||||
uv_once(&once, uv__hrtime_init_once);
|
||||
return mach_continuous_time() * timebase.numer / timebase.denom;
|
||||
}
|
||||
|
||||
@ -334,8 +334,11 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
|
||||
}
|
||||
#endif /* O_CLOEXEC */
|
||||
|
||||
if (req->cb != NULL)
|
||||
if (req->cb != NULL) {
|
||||
uv_rwlock_rdlock(&req->loop->cloexec_lock);
|
||||
/* Tell analyzer we will later release the read lock */
|
||||
uv_rwlock_assume_rdunlocked(&req->loop->cloexec_lock);
|
||||
}
|
||||
|
||||
r = mkstemp(path);
|
||||
|
||||
@ -349,8 +352,11 @@ static int uv__fs_mkstemp(uv_fs_t* req) {
|
||||
r = -1;
|
||||
}
|
||||
|
||||
if (req->cb != NULL)
|
||||
if (req->cb != NULL) {
|
||||
/* Tell analyzer we earlier acquired the read lock */
|
||||
uv_rwlock_assume_rdlocked(&req->loop->cloexec_lock);
|
||||
uv_rwlock_rdunlock(&req->loop->cloexec_lock);
|
||||
}
|
||||
|
||||
clobber:
|
||||
if (r < 0)
|
||||
|
||||
@ -914,7 +914,11 @@ static int uv__spawn_and_init_child(
|
||||
const uv_process_options_t* options,
|
||||
int stdio_count,
|
||||
int (*pipes)[2],
|
||||
pid_t* pid) {
|
||||
pid_t* pid)
|
||||
#if defined(__APPLE__)
|
||||
UV_EXCLUDES(&posix_spawn_init_once)
|
||||
#endif
|
||||
{
|
||||
int signal_pipe[2] = { -1, -1 };
|
||||
int status;
|
||||
int err;
|
||||
@ -1003,7 +1007,11 @@ static int uv__spawn_and_init_child(
|
||||
|
||||
int uv_spawn(uv_loop_t* loop,
|
||||
uv_process_t* process,
|
||||
const uv_process_options_t* options) {
|
||||
const uv_process_options_t* options)
|
||||
#if defined(__APPLE__)
|
||||
UV_EXCLUDES(&posix_spawn_init_once)
|
||||
#endif
|
||||
{
|
||||
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
|
||||
/* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
|
||||
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
|
||||
|
||||
@ -93,7 +93,7 @@ char** uv_setup_args(int argc, char** argv) {
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
int uv_set_process_title(const char* title) UV_EXCLUDES(&process_title_mutex_once, &process_title_mutex) {
|
||||
struct uv__process_title* pt;
|
||||
size_t len;
|
||||
|
||||
@ -124,7 +124,7 @@ int uv_set_process_title(const char* title) {
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
int uv_get_process_title(char* buffer, size_t size) UV_EXCLUDES(&process_title_mutex_once, &process_title_mutex) {
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
|
||||
@ -83,7 +83,7 @@ static void uv__random_devurandom_init(void) {
|
||||
}
|
||||
|
||||
|
||||
int uv__random_devurandom(void* buf, size_t buflen) {
|
||||
int uv__random_devurandom(void* buf, size_t buflen) UV_EXCLUDES(&once) {
|
||||
uv_once(&once, uv__random_devurandom_init);
|
||||
|
||||
if (status != 0)
|
||||
|
||||
@ -36,7 +36,7 @@ static void uv__random_getentropy_init(void) {
|
||||
}
|
||||
|
||||
|
||||
int uv__random_getentropy(void* buf, size_t buflen) {
|
||||
int uv__random_getentropy(void* buf, size_t buflen) UV_EXCLUDES(&once) {
|
||||
size_t pos;
|
||||
size_t stride;
|
||||
|
||||
|
||||
@ -107,7 +107,7 @@ static void uv__signal_global_reinit(void) {
|
||||
}
|
||||
|
||||
|
||||
void uv__signal_global_once_init(void) {
|
||||
void uv__signal_global_once_init(void) UV_EXCLUDES(&uv__signal_global_init_guard) {
|
||||
uv_once(&uv__signal_global_init_guard, uv__signal_global_init);
|
||||
}
|
||||
|
||||
|
||||
@ -315,7 +315,7 @@ int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) {
|
||||
|
||||
int uv_mutex_init(uv_mutex_t* mutex) {
|
||||
#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
|
||||
return UV__ERR(pthread_mutex_init(mutex, NULL));
|
||||
return UV__ERR(pthread_mutex_init(&mutex->m, NULL));
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
int err;
|
||||
@ -326,7 +326,7 @@ int uv_mutex_init(uv_mutex_t* mutex) {
|
||||
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK))
|
||||
abort();
|
||||
|
||||
err = pthread_mutex_init(mutex, &attr);
|
||||
err = pthread_mutex_init(&mutex->m, &attr);
|
||||
|
||||
if (pthread_mutexattr_destroy(&attr))
|
||||
abort();
|
||||
@ -346,7 +346,7 @@ int uv_mutex_init_recursive(uv_mutex_t* mutex) {
|
||||
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
|
||||
abort();
|
||||
|
||||
err = pthread_mutex_init(mutex, &attr);
|
||||
err = pthread_mutex_init(&mutex->m, &attr);
|
||||
|
||||
if (pthread_mutexattr_destroy(&attr))
|
||||
abort();
|
||||
@ -356,21 +356,21 @@ int uv_mutex_init_recursive(uv_mutex_t* mutex) {
|
||||
|
||||
|
||||
void uv_mutex_destroy(uv_mutex_t* mutex) {
|
||||
if (pthread_mutex_destroy(mutex))
|
||||
if (pthread_mutex_destroy(&mutex->m))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_mutex_lock(uv_mutex_t* mutex) {
|
||||
if (pthread_mutex_lock(mutex))
|
||||
void uv_mutex_lock(uv_mutex_t* mutex) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
if (pthread_mutex_lock(&mutex->m))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_mutex_trylock(uv_mutex_t* mutex) {
|
||||
int uv_mutex_trylock(uv_mutex_t* mutex) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_trylock(mutex);
|
||||
err = pthread_mutex_trylock(&mutex->m);
|
||||
if (err) {
|
||||
if (err != EBUSY && err != EAGAIN)
|
||||
abort();
|
||||
@ -381,33 +381,33 @@ int uv_mutex_trylock(uv_mutex_t* mutex) {
|
||||
}
|
||||
|
||||
|
||||
void uv_mutex_unlock(uv_mutex_t* mutex) {
|
||||
if (pthread_mutex_unlock(mutex))
|
||||
void uv_mutex_unlock(uv_mutex_t* mutex) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
if (pthread_mutex_unlock(&mutex->m))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_rwlock_init(uv_rwlock_t* rwlock) {
|
||||
return UV__ERR(pthread_rwlock_init(rwlock, NULL));
|
||||
return UV__ERR(pthread_rwlock_init(&rwlock->rw, NULL));
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_destroy(rwlock))
|
||||
if (pthread_rwlock_destroy(&rwlock->rw))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_rdlock(rwlock))
|
||||
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
if (pthread_rwlock_rdlock(&rwlock->rw))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
|
||||
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
int err;
|
||||
|
||||
err = pthread_rwlock_tryrdlock(rwlock);
|
||||
err = pthread_rwlock_tryrdlock(&rwlock->rw);
|
||||
if (err) {
|
||||
if (err != EBUSY && err != EAGAIN)
|
||||
abort();
|
||||
@ -418,22 +418,22 @@ int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_unlock(rwlock))
|
||||
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
if (pthread_rwlock_unlock(&rwlock->rw))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_wrlock(rwlock))
|
||||
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
if (pthread_rwlock_wrlock(&rwlock->rw))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
|
||||
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
int err;
|
||||
|
||||
err = pthread_rwlock_trywrlock(rwlock);
|
||||
err = pthread_rwlock_trywrlock(&rwlock->rw);
|
||||
if (err) {
|
||||
if (err != EBUSY && err != EAGAIN)
|
||||
abort();
|
||||
@ -444,14 +444,14 @@ int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_unlock(rwlock))
|
||||
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
if (pthread_rwlock_unlock(&rwlock->rw))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_once(uv_once_t* guard, void (*callback)(void)) {
|
||||
if (pthread_once(guard, callback))
|
||||
void uv_once(uv_once_t* guard, void (*callback)(void)) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
if (pthread_once(&guard->o, callback))
|
||||
abort();
|
||||
}
|
||||
|
||||
@ -816,7 +816,7 @@ void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
|
||||
int r;
|
||||
|
||||
errno = 0;
|
||||
r = pthread_cond_wait(cond, mutex);
|
||||
r = pthread_cond_wait(cond, &mutex->m);
|
||||
|
||||
/* Workaround for a bug in OS X at least up to 13.6
|
||||
* See https://github.com/libuv/libuv/issues/4165
|
||||
@ -832,7 +832,7 @@ void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
|
||||
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
|
||||
|
||||
void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
|
||||
if (pthread_cond_wait(cond, mutex))
|
||||
if (pthread_cond_wait(cond, &mutex->m))
|
||||
abort();
|
||||
}
|
||||
|
||||
@ -848,7 +848,7 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
ts.tv_sec = timeout / NANOSEC;
|
||||
ts.tv_nsec = timeout % NANOSEC;
|
||||
r = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
|
||||
r = pthread_cond_timedwait_relative_np(cond, &mutex->m, &ts);
|
||||
#else
|
||||
#if defined(__MVS__)
|
||||
if (gettimeofday(&tv, NULL))
|
||||
@ -859,7 +859,7 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
|
||||
#endif
|
||||
ts.tv_sec = timeout / NANOSEC;
|
||||
ts.tv_nsec = timeout % NANOSEC;
|
||||
r = pthread_cond_timedwait(cond, mutex, &ts);
|
||||
r = pthread_cond_timedwait(cond, &mutex->m, &ts);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@ -90,7 +90,7 @@ static void uv__loops_init(void) {
|
||||
}
|
||||
|
||||
|
||||
static int uv__loops_add(uv_loop_t* loop) {
|
||||
static int uv__loops_add(uv_loop_t* loop) UV_EXCLUDES(&uv__loops_lock) {
|
||||
uv_loop_t** new_loops;
|
||||
int new_capacity, i;
|
||||
|
||||
@ -118,7 +118,7 @@ failed_loops_realloc:
|
||||
}
|
||||
|
||||
|
||||
static void uv__loops_remove(uv_loop_t* loop) {
|
||||
static void uv__loops_remove(uv_loop_t* loop) UV_EXCLUDES(&uv__loops_lock) {
|
||||
int loop_index;
|
||||
int smaller_capacity;
|
||||
uv_loop_t** new_loops;
|
||||
@ -162,7 +162,7 @@ loop_removed:
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
}
|
||||
|
||||
void uv__wake_all_loops(void) {
|
||||
void uv__wake_all_loops(void) UV_EXCLUDES(&uv__loops_lock) {
|
||||
int i;
|
||||
uv_loop_t* loop;
|
||||
|
||||
@ -224,7 +224,7 @@ static void uv__init(void) {
|
||||
}
|
||||
|
||||
|
||||
int uv_loop_init(uv_loop_t* loop) {
|
||||
int uv_loop_init(uv_loop_t* loop) UV_EXCLUDES(&uv__loops_lock) {
|
||||
uv__loop_internal_fields_t* lfields;
|
||||
struct heap* timer_heap;
|
||||
int err;
|
||||
@ -329,12 +329,12 @@ void uv_update_time(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
void uv__once_init(void) {
|
||||
void uv__once_init(void) UV_EXCLUDES(&uv_init_guard_) {
|
||||
uv_once(&uv_init_guard_, uv__init);
|
||||
}
|
||||
|
||||
|
||||
void uv__loop_close(uv_loop_t* loop) {
|
||||
void uv__loop_close(uv_loop_t* loop) UV_EXCLUDES(&uv__loops_lock) {
|
||||
uv__loop_internal_fields_t* lfields;
|
||||
size_t i;
|
||||
|
||||
|
||||
@ -118,7 +118,7 @@ static void uv__fd_hash_init(void) {
|
||||
FIND_IN_GROUP_PTR(UV__FD_HASH_GROUP_SIZE); \
|
||||
} while (0)
|
||||
|
||||
static int uv__fd_hash_get(int fd, struct uv__fd_info_s* info) {
|
||||
static int uv__fd_hash_get(int fd, struct uv__fd_info_s* info) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
FIND_COMMON_VARIABLES
|
||||
|
||||
uv_mutex_lock(&uv__fd_hash_mutex);
|
||||
@ -133,7 +133,7 @@ static int uv__fd_hash_get(int fd, struct uv__fd_info_s* info) {
|
||||
return entry_ptr != NULL;
|
||||
}
|
||||
|
||||
static void uv__fd_hash_add(int fd, struct uv__fd_info_s* info) {
|
||||
static void uv__fd_hash_add(int fd, struct uv__fd_info_s* info) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
FIND_COMMON_VARIABLES
|
||||
|
||||
uv_mutex_lock(&uv__fd_hash_mutex);
|
||||
@ -163,7 +163,7 @@ static void uv__fd_hash_add(int fd, struct uv__fd_info_s* info) {
|
||||
uv_mutex_unlock(&uv__fd_hash_mutex);
|
||||
}
|
||||
|
||||
static int uv__fd_hash_remove(int fd, struct uv__fd_info_s* info) {
|
||||
static int uv__fd_hash_remove(int fd, struct uv__fd_info_s* info) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
FIND_COMMON_VARIABLES
|
||||
|
||||
uv_mutex_lock(&uv__fd_hash_mutex);
|
||||
|
||||
88
src/win/fs.c
88
src/win/fs.c
@ -441,7 +441,7 @@ static void uv__fs_req_init(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
|
||||
void fs__open(uv_fs_t* req) {
|
||||
void fs__open(uv_fs_t* req) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
DWORD access;
|
||||
DWORD share;
|
||||
DWORD disposition;
|
||||
@ -696,7 +696,7 @@ void fs__open(uv_fs_t* req) {
|
||||
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
void fs__close(uv_fs_t* req) {
|
||||
void fs__close(uv_fs_t* req) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int fd = req->file.fd;
|
||||
int result;
|
||||
struct uv__fd_info_s fd_info;
|
||||
@ -746,7 +746,7 @@ LONG fs__filemap_ex_filter(LONG excode, PEXCEPTION_POINTERS pep,
|
||||
}
|
||||
|
||||
|
||||
void fs__read_filemap(uv_fs_t* req, struct uv__fd_info_s* fd_info) {
|
||||
void fs__read_filemap(uv_fs_t* req, struct uv__fd_info_s* fd_info) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int fd = req->file.fd; /* VERIFY_FD done in fs__read */
|
||||
int rw_flags = fd_info->flags &
|
||||
(UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
|
||||
@ -843,7 +843,7 @@ void fs__read_filemap(uv_fs_t* req, struct uv__fd_info_s* fd_info) {
|
||||
return;
|
||||
}
|
||||
|
||||
void fs__read(uv_fs_t* req) {
|
||||
void fs__read(uv_fs_t* req) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int fd = req->file.fd;
|
||||
int64_t offset = req->fs.info.offset;
|
||||
HANDLE handle;
|
||||
@ -930,7 +930,7 @@ void fs__read(uv_fs_t* req) {
|
||||
|
||||
|
||||
void fs__write_filemap(uv_fs_t* req, HANDLE file,
|
||||
struct uv__fd_info_s* fd_info) {
|
||||
struct uv__fd_info_s* fd_info) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int fd = req->file.fd; /* VERIFY_FD done in fs__write */
|
||||
int force_append = fd_info->flags & UV_FS_O_APPEND;
|
||||
int rw_flags = fd_info->flags &
|
||||
@ -1053,7 +1053,7 @@ void fs__write_filemap(uv_fs_t* req, HANDLE file,
|
||||
SET_REQ_RESULT(req, done_write);
|
||||
}
|
||||
|
||||
void fs__write(uv_fs_t* req) {
|
||||
void fs__write(uv_fs_t* req) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int fd = req->file.fd;
|
||||
int64_t offset = req->fs.info.offset;
|
||||
HANDLE handle;
|
||||
@ -2369,7 +2369,7 @@ static void fs__fdatasync(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
static void fs__ftruncate(uv_fs_t* req) {
|
||||
static void fs__ftruncate(uv_fs_t* req) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int fd = req->file.fd;
|
||||
HANDLE handle;
|
||||
struct uv__fd_info_s fd_info = { 0 };
|
||||
@ -3165,7 +3165,7 @@ static void fs__statfs(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
static void uv__fs_work(struct uv__work* w) {
|
||||
static void uv__fs_work(struct uv__work* w) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
uv_fs_t* req;
|
||||
|
||||
req = container_of(w, uv_fs_t, work_req);
|
||||
@ -3263,7 +3263,7 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
|
||||
|
||||
|
||||
int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
|
||||
int mode, uv_fs_cb cb) {
|
||||
int mode, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_OPEN);
|
||||
@ -3279,7 +3279,7 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
|
||||
int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
INIT(UV_FS_CLOSE);
|
||||
req->file.fd = fd;
|
||||
POST;
|
||||
@ -3292,7 +3292,7 @@ int uv_fs_read(uv_loop_t* loop,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
int64_t offset,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
INIT(UV_FS_READ);
|
||||
|
||||
if (bufs == NULL || nbufs == 0) {
|
||||
@ -3325,7 +3325,7 @@ int uv_fs_write(uv_loop_t* loop,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
int64_t offset,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
INIT(UV_FS_WRITE);
|
||||
|
||||
if (bufs == NULL || nbufs == 0) {
|
||||
@ -3358,7 +3358,7 @@ int uv_fs_write(uv_loop_t* loop,
|
||||
|
||||
|
||||
int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_UNLINK);
|
||||
@ -3373,7 +3373,7 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
|
||||
|
||||
int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_MKDIR);
|
||||
@ -3391,7 +3391,7 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
|
||||
int uv_fs_mkdtemp(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* tpl,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_MKDTEMP);
|
||||
@ -3408,7 +3408,7 @@ int uv_fs_mkdtemp(uv_loop_t* loop,
|
||||
int uv_fs_mkstemp(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* tpl,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_MKSTEMP);
|
||||
@ -3422,7 +3422,7 @@ int uv_fs_mkstemp(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_RMDIR);
|
||||
@ -3437,7 +3437,7 @@ int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
|
||||
|
||||
int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_SCANDIR);
|
||||
@ -3454,7 +3454,7 @@ int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
|
||||
int uv_fs_opendir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_OPENDIR);
|
||||
@ -3469,7 +3469,7 @@ int uv_fs_opendir(uv_loop_t* loop,
|
||||
int uv_fs_readdir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uv_dir_t* dir,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
INIT(UV_FS_READDIR);
|
||||
|
||||
if (dir == NULL ||
|
||||
@ -3486,7 +3486,7 @@ int uv_fs_readdir(uv_loop_t* loop,
|
||||
int uv_fs_closedir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uv_dir_t* dir,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
INIT(UV_FS_CLOSEDIR);
|
||||
if (dir == NULL) {
|
||||
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
|
||||
@ -3497,7 +3497,7 @@ int uv_fs_closedir(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
const char* new_path, uv_fs_cb cb) {
|
||||
const char* new_path, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_LINK);
|
||||
@ -3512,7 +3512,7 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
|
||||
|
||||
int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
const char* new_path, int flags, uv_fs_cb cb) {
|
||||
const char* new_path, int flags, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_SYMLINK);
|
||||
@ -3528,7 +3528,7 @@ int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
|
||||
|
||||
int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_READLINK);
|
||||
@ -3543,7 +3543,7 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
|
||||
|
||||
int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_REALPATH);
|
||||
@ -3564,7 +3564,7 @@ int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
|
||||
|
||||
int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
|
||||
uv_gid_t gid, uv_fs_cb cb) {
|
||||
uv_gid_t gid, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_CHOWN);
|
||||
@ -3579,14 +3579,14 @@ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
|
||||
|
||||
|
||||
int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid,
|
||||
uv_gid_t gid, uv_fs_cb cb) {
|
||||
uv_gid_t gid, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
INIT(UV_FS_FCHOWN);
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
|
||||
uv_gid_t gid, uv_fs_cb cb) {
|
||||
uv_gid_t gid, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_LCHOWN);
|
||||
@ -3600,7 +3600,7 @@ int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_STAT);
|
||||
@ -3614,7 +3614,7 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_LSTAT);
|
||||
@ -3628,7 +3628,7 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
|
||||
int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
INIT(UV_FS_FSTAT);
|
||||
req->file.fd = fd;
|
||||
POST;
|
||||
@ -3636,7 +3636,7 @@ int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
|
||||
|
||||
|
||||
int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
const char* new_path, uv_fs_cb cb) {
|
||||
const char* new_path, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_RENAME);
|
||||
@ -3650,14 +3650,14 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
|
||||
int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
INIT(UV_FS_FSYNC);
|
||||
req->file.fd = fd;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
|
||||
int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
INIT(UV_FS_FDATASYNC);
|
||||
req->file.fd = fd;
|
||||
POST;
|
||||
@ -3665,7 +3665,7 @@ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
|
||||
|
||||
|
||||
int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd,
|
||||
int64_t offset, uv_fs_cb cb) {
|
||||
int64_t offset, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
INIT(UV_FS_FTRUNCATE);
|
||||
req->file.fd = fd;
|
||||
req->fs.info.offset = offset;
|
||||
@ -3678,7 +3678,7 @@ int uv_fs_copyfile(uv_loop_t* loop,
|
||||
const char* path,
|
||||
const char* new_path,
|
||||
int flags,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_COPYFILE);
|
||||
@ -3702,7 +3702,7 @@ int uv_fs_copyfile(uv_loop_t* loop,
|
||||
|
||||
|
||||
int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
|
||||
uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
|
||||
uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
INIT(UV_FS_SENDFILE);
|
||||
req->file.fd = fd_in;
|
||||
req->fs.info.fd_out = fd_out;
|
||||
@ -3718,7 +3718,7 @@ int uv_fs_access(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
int flags,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_ACCESS);
|
||||
@ -3734,7 +3734,7 @@ int uv_fs_access(uv_loop_t* loop,
|
||||
|
||||
|
||||
int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_CHMOD);
|
||||
@ -3750,7 +3750,7 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
|
||||
|
||||
|
||||
int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
INIT(UV_FS_FCHMOD);
|
||||
req->file.fd = fd;
|
||||
req->fs.info.mode = mode;
|
||||
@ -3759,7 +3759,7 @@ int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
|
||||
|
||||
|
||||
int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
|
||||
double mtime, uv_fs_cb cb) {
|
||||
double mtime, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_UTIME);
|
||||
@ -3776,7 +3776,7 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
|
||||
|
||||
|
||||
int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
|
||||
double mtime, uv_fs_cb cb) {
|
||||
double mtime, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
INIT(UV_FS_FUTIME);
|
||||
req->file.fd = fd;
|
||||
req->fs.time.atime = atime;
|
||||
@ -3785,7 +3785,7 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
|
||||
}
|
||||
|
||||
int uv_fs_lutime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
|
||||
double mtime, uv_fs_cb cb) {
|
||||
double mtime, uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_LUTIME);
|
||||
@ -3804,7 +3804,7 @@ int uv_fs_lutime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
|
||||
int uv_fs_statfs(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_fs_cb cb) {
|
||||
uv_fs_cb cb) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_STATFS);
|
||||
|
||||
@ -63,7 +63,7 @@ static void uv__init_overlapped_dummy(void) {
|
||||
}
|
||||
|
||||
|
||||
static OVERLAPPED* uv__get_overlapped_dummy(void) {
|
||||
static OVERLAPPED* uv__get_overlapped_dummy(void) UV_EXCLUDES(&overlapped_dummy_init_guard_) {
|
||||
uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy);
|
||||
return &overlapped_dummy_;
|
||||
}
|
||||
@ -530,7 +530,7 @@ void uv__process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
|
||||
}
|
||||
|
||||
|
||||
int uv__poll_close(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
int uv__poll_close(uv_loop_t* loop, uv_poll_t* handle) UV_EXCLUDES(&overlapped_dummy_init_guard_) {
|
||||
AFD_POLL_INFO afd_poll_info;
|
||||
DWORD error;
|
||||
int result;
|
||||
|
||||
@ -895,7 +895,7 @@ void uv__process_endgame(uv_loop_t* loop, uv_process_t* handle) {
|
||||
|
||||
int uv_spawn(uv_loop_t* loop,
|
||||
uv_process_t* process,
|
||||
const uv_process_options_t* options) {
|
||||
const uv_process_options_t* options) UV_EXCLUDES(&uv_global_job_handle_init_guard_) {
|
||||
int i;
|
||||
int err = 0;
|
||||
WCHAR* path = NULL, *alloc_path = NULL;
|
||||
|
||||
@ -46,7 +46,7 @@ static BOOL WINAPI uv__once_inner(INIT_ONCE *once, void* param, void** context)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void uv_once(uv_once_t* guard, uv__once_cb callback) {
|
||||
void uv_once(uv_once_t* guard, uv__once_cb callback) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
uv__once_data_t data = { .callback = callback };
|
||||
InitOnceExecuteOnce(&guard->init_once, uv__once_inner, (void*) &data, NULL);
|
||||
}
|
||||
@ -75,7 +75,7 @@ struct thread_ctx {
|
||||
};
|
||||
|
||||
|
||||
static UINT __stdcall uv__thread_start(void* arg) {
|
||||
static UINT __stdcall uv__thread_start(void* arg) UV_EXCLUDES(&uv__current_thread_init_guard) {
|
||||
struct thread_ctx *ctx_p;
|
||||
struct thread_ctx ctx;
|
||||
|
||||
@ -246,7 +246,8 @@ int uv_thread_getcpu(void) {
|
||||
return GetCurrentProcessorNumber();
|
||||
}
|
||||
|
||||
uv_thread_t uv_thread_self(void) {
|
||||
|
||||
uv_thread_t uv_thread_self(void) UV_EXCLUDES(&uv__current_thread_init_guard) {
|
||||
uv_thread_t key;
|
||||
uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
|
||||
key = uv_key_get(&uv__current_thread_key);
|
||||
@ -368,7 +369,7 @@ int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) {
|
||||
|
||||
|
||||
int uv_mutex_init(uv_mutex_t* mutex) {
|
||||
InitializeCriticalSection(mutex);
|
||||
InitializeCriticalSection(&mutex->cs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -379,25 +380,25 @@ int uv_mutex_init_recursive(uv_mutex_t* mutex) {
|
||||
|
||||
|
||||
void uv_mutex_destroy(uv_mutex_t* mutex) {
|
||||
DeleteCriticalSection(mutex);
|
||||
DeleteCriticalSection(&mutex->cs);
|
||||
}
|
||||
|
||||
|
||||
void uv_mutex_lock(uv_mutex_t* mutex) {
|
||||
EnterCriticalSection(mutex);
|
||||
void uv_mutex_lock(uv_mutex_t* mutex) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
EnterCriticalSection(&mutex->cs);
|
||||
}
|
||||
|
||||
|
||||
int uv_mutex_trylock(uv_mutex_t* mutex) {
|
||||
if (TryEnterCriticalSection(mutex))
|
||||
int uv_mutex_trylock(uv_mutex_t* mutex) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
if (TryEnterCriticalSection(&mutex->cs))
|
||||
return 0;
|
||||
else
|
||||
return UV_EBUSY;
|
||||
}
|
||||
|
||||
|
||||
void uv_mutex_unlock(uv_mutex_t* mutex) {
|
||||
LeaveCriticalSection(mutex);
|
||||
void uv_mutex_unlock(uv_mutex_t* mutex) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
LeaveCriticalSection(&mutex->cs);
|
||||
}
|
||||
|
||||
/* Ensure that the ABI for this type remains stable in v1.x */
|
||||
@ -421,12 +422,12 @@ void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
|
||||
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
AcquireSRWLockShared(&rwlock->read_write_lock_);
|
||||
}
|
||||
|
||||
|
||||
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
|
||||
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
if (!TryAcquireSRWLockShared(&rwlock->read_write_lock_))
|
||||
return UV_EBUSY;
|
||||
|
||||
@ -434,17 +435,17 @@ int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
|
||||
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
ReleaseSRWLockShared(&rwlock->read_write_lock_);
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
|
||||
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
AcquireSRWLockExclusive(&rwlock->read_write_lock_);
|
||||
}
|
||||
|
||||
|
||||
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
|
||||
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
if (!TryAcquireSRWLockExclusive(&rwlock->read_write_lock_))
|
||||
return UV_EBUSY;
|
||||
|
||||
@ -452,7 +453,7 @@ int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
|
||||
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
ReleaseSRWLockExclusive(&rwlock->read_write_lock_);
|
||||
}
|
||||
|
||||
@ -521,13 +522,13 @@ void uv_cond_broadcast(uv_cond_t* cond) {
|
||||
|
||||
|
||||
void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
|
||||
if (!SleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
|
||||
if (!SleepConditionVariableCS(&cond->cond_var, &mutex->cs, INFINITE))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
|
||||
if (SleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
|
||||
if (SleepConditionVariableCS(&cond->cond_var, &mutex->cs, (DWORD)(timeout / 1e6)))
|
||||
return 0;
|
||||
if (GetLastError() != ERROR_TIMEOUT)
|
||||
abort();
|
||||
|
||||
@ -2425,7 +2425,7 @@ static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uv__tty_console_signal_resize(void) {
|
||||
static void uv__tty_console_signal_resize(void) UV_EXCLUDES(&uv__tty_console_resize_mutex) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO sb_info;
|
||||
int width, height;
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ static int prepare_cb_called;
|
||||
static int close_cb_called;
|
||||
|
||||
|
||||
static void thread_cb(void *arg) {
|
||||
static void thread_cb(void *arg) UV_EXCLUDES(&mutex) {
|
||||
int n;
|
||||
int r;
|
||||
|
||||
@ -75,7 +75,7 @@ static void close_cb(uv_handle_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
static void async_cb(uv_async_t* handle) {
|
||||
static void async_cb(uv_async_t* handle) UV_EXCLUDES(&mutex) {
|
||||
int n;
|
||||
|
||||
ASSERT_PTR_EQ(handle, &async);
|
||||
@ -99,13 +99,14 @@ static void prepare_cb(uv_prepare_t* handle) {
|
||||
if (prepare_cb_called++)
|
||||
return;
|
||||
|
||||
uv_mutex_assume_locked(&mutex);
|
||||
r = uv_thread_create(&thread, thread_cb, NULL);
|
||||
ASSERT_OK(r);
|
||||
uv_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(async) {
|
||||
TEST_IMPL(async) UV_EXCLUDES(&mutex) {
|
||||
int r;
|
||||
|
||||
r = uv_mutex_init(&mutex);
|
||||
@ -115,8 +116,11 @@ TEST_IMPL(async) {
|
||||
r = uv_prepare_init(uv_default_loop(), &prepare);
|
||||
ASSERT_OK(r);
|
||||
r = uv_prepare_start(&prepare, prepare_cb);
|
||||
/* This is true since prepare_cb must run at least once before async_cb. */
|
||||
uv_mutex_assume_unlocked(&mutex);
|
||||
ASSERT_OK(r);
|
||||
|
||||
uv_mutex_assert_unlocked(&mutex);
|
||||
r = uv_async_init(uv_default_loop(), &async, async_cb);
|
||||
ASSERT_OK(r);
|
||||
|
||||
|
||||
@ -34,19 +34,19 @@
|
||||
#define FD_DIFF 9
|
||||
|
||||
|
||||
void assert_nonexistent(int fd) {
|
||||
void assert_nonexistent(int fd) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
struct uv__fd_info_s info = { 0 };
|
||||
ASSERT(!uv__fd_hash_get(fd, &info));
|
||||
ASSERT(!uv__fd_hash_remove(fd, &info));
|
||||
}
|
||||
|
||||
void assert_existent(int fd) {
|
||||
void assert_existent(int fd) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
struct uv__fd_info_s info = { 0 };
|
||||
ASSERT(uv__fd_hash_get(fd, &info));
|
||||
ASSERT_EQ(info.flags, fd + FD_DIFF);
|
||||
}
|
||||
|
||||
void assert_insertion(int fd) {
|
||||
void assert_insertion(int fd) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
struct uv__fd_info_s info = { 0 };
|
||||
assert_nonexistent(fd);
|
||||
info.flags = fd + FD_DIFF;
|
||||
@ -54,7 +54,7 @@ void assert_insertion(int fd) {
|
||||
assert_existent(fd);
|
||||
}
|
||||
|
||||
void assert_removal(int fd) {
|
||||
void assert_removal(int fd) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
struct uv__fd_info_s info = { 0 };
|
||||
assert_existent(fd);
|
||||
uv__fd_hash_remove(fd, &info);
|
||||
@ -88,7 +88,7 @@ void assert_removal(int fd) {
|
||||
} while (0)
|
||||
|
||||
|
||||
TEST_IMPL(fs_fd_hash) {
|
||||
TEST_IMPL(fs_fd_hash) UV_EXCLUDES(&uv__fd_hash_mutex) {
|
||||
int fd;
|
||||
|
||||
uv__fd_hash_init();
|
||||
|
||||
@ -50,7 +50,7 @@ TEST_IMPL(thread_mutex) {
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(thread_mutex_recursive) {
|
||||
TEST_IMPL(thread_mutex_recursive) UV_NO_THREAD_SAFETY_ANALYSIS {
|
||||
uv_mutex_t mutex;
|
||||
int r;
|
||||
|
||||
@ -88,14 +88,14 @@ TEST_IMPL(thread_rwlock) {
|
||||
|
||||
|
||||
/* Call when holding |mutex|. */
|
||||
static void synchronize_nowait(void) {
|
||||
static void synchronize_nowait(void) UV_REQUIRES(&mutex) {
|
||||
step += 1;
|
||||
uv_cond_signal(&condvar);
|
||||
}
|
||||
|
||||
|
||||
/* Call when holding |mutex|. */
|
||||
static void synchronize(void) {
|
||||
static void synchronize(void) UV_REQUIRES(&mutex) {
|
||||
int current;
|
||||
|
||||
synchronize_nowait();
|
||||
@ -105,7 +105,7 @@ static void synchronize(void) {
|
||||
}
|
||||
|
||||
|
||||
static void thread_rwlock_trylock_peer(void* unused) {
|
||||
static void thread_rwlock_trylock_peer(void* unused) UV_EXCLUDES(&mutex, &rwlock) {
|
||||
(void) &unused;
|
||||
|
||||
uv_mutex_lock(&mutex);
|
||||
@ -136,7 +136,7 @@ static void thread_rwlock_trylock_peer(void* unused) {
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(thread_rwlock_trylock) {
|
||||
TEST_IMPL(thread_rwlock_trylock) UV_EXCLUDES(&mutex, &rwlock) {
|
||||
uv_thread_t thread;
|
||||
|
||||
ASSERT_OK(uv_cond_init(&condvar));
|
||||
|
||||
@ -51,35 +51,43 @@ enum signal_action {
|
||||
|
||||
static uv_sem_t sem;
|
||||
static uv_mutex_t lock;
|
||||
static int stop = 0;
|
||||
static int stop UV_GUARDED_BY(&lock) = 0;
|
||||
|
||||
static int signal1_cb_counter = 0;
|
||||
static int signal2_cb_counter = 0;
|
||||
static int loop_creation_counter = 0;
|
||||
static int signal1_cb_counter UV_GUARDED_BY(&lock) = 0;
|
||||
static int signal2_cb_counter UV_GUARDED_BY(&lock) = 0;
|
||||
static int loop_creation_counter UV_GUARDED_BY(&lock) = 0;
|
||||
|
||||
|
||||
static void increment_counter(int* counter) {
|
||||
/* Since clang analyzer cannot handle the implications of UV_PT_GUARDED_BY on a
|
||||
* parameter, define this using a macro instead for now:
|
||||
static void increment_counter(int* counter UV_PT_GUARDED_BY(&lock)) UV_EXCLUDES(&lock) {
|
||||
uv_mutex_lock(&lock);
|
||||
++(*counter);
|
||||
uv_mutex_unlock(&lock);
|
||||
}
|
||||
*/
|
||||
|
||||
#define increment_counter(counter) \
|
||||
uv_mutex_lock(&lock); \
|
||||
++(*counter); \
|
||||
uv_mutex_unlock(&lock);
|
||||
|
||||
|
||||
static void signal1_cb(uv_signal_t* handle, int signum) {
|
||||
static void signal1_cb(uv_signal_t* handle, int signum) UV_EXCLUDES(&lock) {
|
||||
ASSERT_EQ(signum, SIGUSR1);
|
||||
increment_counter(&signal1_cb_counter);
|
||||
uv_signal_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
static void signal2_cb(uv_signal_t* handle, int signum) {
|
||||
static void signal2_cb(uv_signal_t* handle, int signum) UV_EXCLUDES(&lock) {
|
||||
ASSERT_EQ(signum, SIGUSR2);
|
||||
increment_counter(&signal2_cb_counter);
|
||||
uv_signal_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
static void signal_handling_worker(void* context) {
|
||||
static void signal_handling_worker(void* context) UV_EXCLUDES(&lock) {
|
||||
enum signal_action action;
|
||||
uv_signal_t signal1a;
|
||||
uv_signal_t signal1b;
|
||||
@ -156,12 +164,12 @@ static void signal_handling_worker(void* context) {
|
||||
}
|
||||
|
||||
|
||||
static void signal_unexpected_cb(uv_signal_t* handle, int signum) {
|
||||
static void signal_unexpected_cb(uv_signal_t* handle, int signum) UV_EXCLUDES(&lock) {
|
||||
ASSERT(0 && "signal_unexpected_cb should never be called");
|
||||
}
|
||||
|
||||
|
||||
static void loop_creating_worker(void* context) {
|
||||
static void loop_creating_worker(void* context) UV_EXCLUDES(&lock) {
|
||||
int done;
|
||||
|
||||
(void) context;
|
||||
@ -198,7 +206,7 @@ static void loop_creating_worker(void* context) {
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(signal_multiple_loops) {
|
||||
TEST_IMPL(signal_multiple_loops) UV_EXCLUDES(&lock) {
|
||||
#if defined(__CYGWIN__) || defined(__MSYS__)
|
||||
/* FIXME: This test needs more investigation. Somehow the `read` in
|
||||
uv__signal_lock fails spuriously with EACCES or even EAGAIN even
|
||||
@ -299,6 +307,8 @@ TEST_IMPL(signal_multiple_loops) {
|
||||
}
|
||||
|
||||
uv_sem_destroy(&sem);
|
||||
|
||||
uv_mutex_lock(&lock); /* Unnecessary but makes static analysis happy. */
|
||||
printf("signal1_cb calls: %d\n", signal1_cb_counter);
|
||||
printf("signal2_cb calls: %d\n", signal2_cb_counter);
|
||||
printf("loops created and destroyed: %d\n", loop_creation_counter);
|
||||
@ -313,6 +323,7 @@ TEST_IMPL(signal_multiple_loops) {
|
||||
* least there should be 1 for every loop creating thread.
|
||||
*/
|
||||
ASSERT_GE(loop_creation_counter, NUM_LOOP_CREATING_THREADS);
|
||||
uv_mutex_unlock(&lock);
|
||||
|
||||
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
||||
return 0;
|
||||
|
||||
@ -80,7 +80,7 @@ static void on_close(uv_handle_t* handle) {
|
||||
free(handle);
|
||||
}
|
||||
|
||||
static void ticktack(uv_timer_t* timer) {
|
||||
static void ticktack(uv_timer_t* timer) UV_EXCLUDES(&mutex) {
|
||||
ASSERT(timer == &thread_timer_handle1 || timer == &thread_timer_handle2);
|
||||
|
||||
int done = 0;
|
||||
@ -99,8 +99,7 @@ static void ticktack(uv_timer_t* timer) {
|
||||
}
|
||||
}
|
||||
|
||||
static void on_connection(uv_stream_t* server, int status)
|
||||
{
|
||||
static void on_connection(uv_stream_t* server, int status) UV_EXCLUDES(&mutex) {
|
||||
ASSERT_OK(status);
|
||||
ASSERT(server == (uv_stream_t*) &thread_handle1 || \
|
||||
server == (uv_stream_t*) &thread_handle2);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user