unix,win: add uv_mutex_init_recursive()
Support the creation of recursive mutexes on Unix. A matching API is added on Windows, however mutexes on Windows are always recursive. Refs: https://github.com/libuv/libuv/issues/1022 PR-URL: https://github.com/libuv/libuv/pull/1555 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
parent
5b6eead064
commit
ec96b55438
@ -79,18 +79,21 @@ The mutex functions are a **direct** map to the pthread equivalents.
|
|||||||
.. literalinclude:: ../../../include/uv.h
|
.. literalinclude:: ../../../include/uv.h
|
||||||
:lines: 1355-1360
|
:lines: 1355-1360
|
||||||
|
|
||||||
The ``uv_mutex_init()`` and ``uv_mutex_trylock()`` functions will return 0 on
|
The ``uv_mutex_init()``, ``uv_mutex_init_recursive()`` and ``uv_mutex_trylock()``
|
||||||
success, and an error code otherwise.
|
functions will return 0 on success, and an error code otherwise.
|
||||||
|
|
||||||
If `libuv` has been compiled with debugging enabled, ``uv_mutex_destroy()``,
|
If `libuv` has been compiled with debugging enabled, ``uv_mutex_destroy()``,
|
||||||
``uv_mutex_lock()`` and ``uv_mutex_unlock()`` will ``abort()`` on error.
|
``uv_mutex_lock()`` and ``uv_mutex_unlock()`` will ``abort()`` on error.
|
||||||
Similarly ``uv_mutex_trylock()`` will abort if the error is anything *other
|
Similarly ``uv_mutex_trylock()`` will abort if the error is anything *other
|
||||||
than* ``EAGAIN`` or ``EBUSY``.
|
than* ``EAGAIN`` or ``EBUSY``.
|
||||||
|
|
||||||
Recursive mutexes are supported by some platforms, but you should not rely on
|
Recursive mutexes are supported, but you should not rely on them. Also, they
|
||||||
them. The BSD mutex implementation will raise an error if a thread which has
|
should not be used with ``uv_cond_t`` variables.
|
||||||
|
|
||||||
|
The default BSD mutex implementation will raise an error if a thread which has
|
||||||
locked a mutex attempts to lock it again. For example, a construct like::
|
locked a mutex attempts to lock it again. For example, a construct like::
|
||||||
|
|
||||||
|
uv_mutex_init(a_mutex);
|
||||||
uv_mutex_lock(a_mutex);
|
uv_mutex_lock(a_mutex);
|
||||||
uv_thread_create(thread_id, entry, (void *)a_mutex);
|
uv_thread_create(thread_id, entry, (void *)a_mutex);
|
||||||
uv_mutex_lock(a_mutex);
|
uv_mutex_lock(a_mutex);
|
||||||
@ -102,8 +105,7 @@ return an error in the second call to ``uv_mutex_lock()``.
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Mutexes on linux support attributes for a recursive mutex, but the API is
|
Mutexes on Windows are always recursive.
|
||||||
not exposed via libuv.
|
|
||||||
|
|
||||||
Locks
|
Locks
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|||||||
@ -91,6 +91,7 @@ Functions return 0 on success or an error code < 0 (unless the
|
|||||||
return type is void, of course).
|
return type is void, of course).
|
||||||
|
|
||||||
.. c:function:: int uv_mutex_init(uv_mutex_t* handle)
|
.. c:function:: int uv_mutex_init(uv_mutex_t* handle)
|
||||||
|
.. c:function:: int uv_mutex_init_recursive(uv_mutex_t* handle)
|
||||||
.. c:function:: void uv_mutex_destroy(uv_mutex_t* handle)
|
.. c:function:: void uv_mutex_destroy(uv_mutex_t* handle)
|
||||||
.. c:function:: void uv_mutex_lock(uv_mutex_t* handle)
|
.. c:function:: void uv_mutex_lock(uv_mutex_t* handle)
|
||||||
.. c:function:: int uv_mutex_trylock(uv_mutex_t* handle)
|
.. c:function:: int uv_mutex_trylock(uv_mutex_t* handle)
|
||||||
|
|||||||
@ -1424,6 +1424,7 @@ 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 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(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_destroy(uv_mutex_t* handle);
|
||||||
UV_EXTERN void uv_mutex_lock(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 int uv_mutex_trylock(uv_mutex_t* handle);
|
||||||
|
|||||||
@ -241,6 +241,25 @@ int uv_mutex_init(uv_mutex_t* mutex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_mutex_init_recursive(uv_mutex_t* mutex) {
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (pthread_mutexattr_init(&attr))
|
||||||
|
abort();
|
||||||
|
|
||||||
|
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
|
||||||
|
abort();
|
||||||
|
|
||||||
|
err = pthread_mutex_init(mutex, &attr);
|
||||||
|
|
||||||
|
if (pthread_mutexattr_destroy(&attr))
|
||||||
|
abort();
|
||||||
|
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void uv_mutex_destroy(uv_mutex_t* mutex) {
|
void uv_mutex_destroy(uv_mutex_t* mutex) {
|
||||||
if (pthread_mutex_destroy(mutex))
|
if (pthread_mutex_destroy(mutex))
|
||||||
abort();
|
abort();
|
||||||
|
|||||||
@ -198,6 +198,11 @@ int uv_mutex_init(uv_mutex_t* mutex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_mutex_init_recursive(uv_mutex_t* mutex) {
|
||||||
|
return uv_mutex_init(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void uv_mutex_destroy(uv_mutex_t* mutex) {
|
void uv_mutex_destroy(uv_mutex_t* mutex) {
|
||||||
DeleteCriticalSection(mutex);
|
DeleteCriticalSection(mutex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -328,6 +328,7 @@ TEST_DECLARE (threadpool_cancel_single)
|
|||||||
TEST_DECLARE (thread_local_storage)
|
TEST_DECLARE (thread_local_storage)
|
||||||
TEST_DECLARE (thread_stack_size)
|
TEST_DECLARE (thread_stack_size)
|
||||||
TEST_DECLARE (thread_mutex)
|
TEST_DECLARE (thread_mutex)
|
||||||
|
TEST_DECLARE (thread_mutex_recursive)
|
||||||
TEST_DECLARE (thread_rwlock)
|
TEST_DECLARE (thread_rwlock)
|
||||||
TEST_DECLARE (thread_rwlock_trylock)
|
TEST_DECLARE (thread_rwlock_trylock)
|
||||||
TEST_DECLARE (thread_create)
|
TEST_DECLARE (thread_create)
|
||||||
@ -840,6 +841,7 @@ TASK_LIST_START
|
|||||||
TEST_ENTRY (thread_local_storage)
|
TEST_ENTRY (thread_local_storage)
|
||||||
TEST_ENTRY (thread_stack_size)
|
TEST_ENTRY (thread_stack_size)
|
||||||
TEST_ENTRY (thread_mutex)
|
TEST_ENTRY (thread_mutex)
|
||||||
|
TEST_ENTRY (thread_mutex_recursive)
|
||||||
TEST_ENTRY (thread_rwlock)
|
TEST_ENTRY (thread_rwlock)
|
||||||
TEST_ENTRY (thread_rwlock_trylock)
|
TEST_ENTRY (thread_rwlock_trylock)
|
||||||
TEST_ENTRY (thread_create)
|
TEST_ENTRY (thread_create)
|
||||||
|
|||||||
@ -50,6 +50,26 @@ TEST_IMPL(thread_mutex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_IMPL(thread_mutex_recursive) {
|
||||||
|
uv_mutex_t mutex;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = uv_mutex_init_recursive(&mutex);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
|
||||||
|
uv_mutex_lock(&mutex);
|
||||||
|
uv_mutex_lock(&mutex);
|
||||||
|
ASSERT(0 == uv_mutex_trylock(&mutex));
|
||||||
|
|
||||||
|
uv_mutex_unlock(&mutex);
|
||||||
|
uv_mutex_unlock(&mutex);
|
||||||
|
uv_mutex_unlock(&mutex);
|
||||||
|
uv_mutex_destroy(&mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_IMPL(thread_rwlock) {
|
TEST_IMPL(thread_rwlock) {
|
||||||
uv_rwlock_t rwlock;
|
uv_rwlock_t rwlock;
|
||||||
int r;
|
int r;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user