mirror of
https://github.com/libuv/libuv
synced 2025-03-28 21:13:16 +00:00
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
|
||||
:lines: 1355-1360
|
||||
|
||||
The ``uv_mutex_init()`` and ``uv_mutex_trylock()`` functions will return 0 on
|
||||
success, and an error code otherwise.
|
||||
The ``uv_mutex_init()``, ``uv_mutex_init_recursive()`` and ``uv_mutex_trylock()``
|
||||
functions will return 0 on success, and an error code otherwise.
|
||||
|
||||
If `libuv` has been compiled with debugging enabled, ``uv_mutex_destroy()``,
|
||||
``uv_mutex_lock()`` and ``uv_mutex_unlock()`` will ``abort()`` on error.
|
||||
Similarly ``uv_mutex_trylock()`` will abort if the error is anything *other
|
||||
than* ``EAGAIN`` or ``EBUSY``.
|
||||
|
||||
Recursive mutexes are supported by some platforms, but you should not rely on
|
||||
them. The BSD mutex implementation will raise an error if a thread which has
|
||||
Recursive mutexes are supported, but you should not rely on them. Also, they
|
||||
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::
|
||||
|
||||
uv_mutex_init(a_mutex);
|
||||
uv_mutex_lock(a_mutex);
|
||||
uv_thread_create(thread_id, entry, (void *)a_mutex);
|
||||
uv_mutex_lock(a_mutex);
|
||||
@ -102,8 +105,7 @@ return an error in the second call to ``uv_mutex_lock()``.
|
||||
|
||||
.. note::
|
||||
|
||||
Mutexes on linux support attributes for a recursive mutex, but the API is
|
||||
not exposed via libuv.
|
||||
Mutexes on Windows are always recursive.
|
||||
|
||||
Locks
|
||||
~~~~~
|
||||
|
@ -91,6 +91,7 @@ Functions return 0 on success or an error code < 0 (unless the
|
||||
return type is void, of course).
|
||||
|
||||
.. 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_lock(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 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);
|
||||
|
@ -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) {
|
||||
if (pthread_mutex_destroy(mutex))
|
||||
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) {
|
||||
DeleteCriticalSection(mutex);
|
||||
}
|
||||
|
@ -328,6 +328,7 @@ TEST_DECLARE (threadpool_cancel_single)
|
||||
TEST_DECLARE (thread_local_storage)
|
||||
TEST_DECLARE (thread_stack_size)
|
||||
TEST_DECLARE (thread_mutex)
|
||||
TEST_DECLARE (thread_mutex_recursive)
|
||||
TEST_DECLARE (thread_rwlock)
|
||||
TEST_DECLARE (thread_rwlock_trylock)
|
||||
TEST_DECLARE (thread_create)
|
||||
@ -840,6 +841,7 @@ TASK_LIST_START
|
||||
TEST_ENTRY (thread_local_storage)
|
||||
TEST_ENTRY (thread_stack_size)
|
||||
TEST_ENTRY (thread_mutex)
|
||||
TEST_ENTRY (thread_mutex_recursive)
|
||||
TEST_ENTRY (thread_rwlock)
|
||||
TEST_ENTRY (thread_rwlock_trylock)
|
||||
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) {
|
||||
uv_rwlock_t rwlock;
|
||||
int r;
|
||||
|
Loading…
x
Reference in New Issue
Block a user