1
0
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:
Scott Parker 2017-09-21 10:36:20 -07:00 committed by cjihrig
parent 5b6eead064
commit ec96b55438
No known key found for this signature in database
GPG Key ID: 7434390BDBE9B9C5
7 changed files with 56 additions and 6 deletions

View File

@ -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
~~~~~

View File

@ -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)

View File

@ -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);

View File

@ -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();

View File

@ -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);
}

View File

@ -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)

View File

@ -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;