Skip to content
Snippets Groups Projects
Commit f36ddb9f authored by Deucе's avatar Deucе :ok_hand_tone4:
Browse files

Fix rwlock_unlock() and rwlock_rdlock() recursion.

It would be nice to use TLS for the recusrion counter, but on Windows,
it looks like TLS in threads created after the object is created is
uninitialized, so we would need some kind of thread start hook thingie
which just seems like too much work.

Instead, rely on the old standby single-linked list to track.
parent 82b89922
No related branches found
No related tags found
No related merge requests found
Pipeline #5299 canceled
...@@ -6,6 +6,32 @@ ...@@ -6,6 +6,32 @@
#elif defined(_WIN32) #elif defined(_WIN32)
#include <stdlib.h>
static struct rwlock_reader_thread *
find_self(rwlock_t *lock, struct rwlock_reader_thread ***prev)
{
DWORD self = GetCurrentThreadId();
struct rwlock_reader_thread *ret;
if (prev)
*prev = &lock->rthreads;
for (ret = NULL; ret; ret = ret->next) {
if (ret->id == self)
return ret;
if (prev) {
*prev = &ret->next;
}
}
ret = calloc(1, sizeof(*ret));
if (ret == NULL)
return ret;
ret->next = lock->rthreads;
ret->id = self;
lock->rthreads = ret;
return ret;
}
BOOL BOOL
rwlock_init(rwlock_t *lock) rwlock_init(rwlock_t *lock)
{ {
...@@ -15,14 +41,22 @@ rwlock_init(rwlock_t *lock) ...@@ -15,14 +41,22 @@ rwlock_init(rwlock_t *lock)
lock->writers = 0; lock->writers = 0;
lock->writers_waiting = 0; lock->writers_waiting = 0;
lock->writer = (DWORD)-1; lock->writer = (DWORD)-1;
lock->rthreads = NULL;
return TRUE; return TRUE;
} }
BOOL BOOL
rwlock_rdlock(rwlock_t *lock) rwlock_rdlock(rwlock_t *lock)
{ {
struct rwlock_reader_thread *rc;
EnterCriticalSection(&lock->lk); EnterCriticalSection(&lock->lk);
while(lock->writers || lock->writers_waiting) { rc = find_self(lock, NULL);
if (rc == NULL) {
LeaveCriticalSection(&lock->lk);
return FALSE;
}
while(rc->count == 0 && (lock->writers || lock->writers_waiting)) {
LeaveCriticalSection(&lock->lk); LeaveCriticalSection(&lock->lk);
// Wait for current writer to release // Wait for current writer to release
EnterCriticalSection(&lock->wlk); EnterCriticalSection(&lock->wlk);
...@@ -40,12 +74,14 @@ rwlock_rdlock(rwlock_t *lock) ...@@ -40,12 +74,14 @@ rwlock_rdlock(rwlock_t *lock)
} }
else { else {
lock->readers++; lock->readers++;
rc->count++;
LeaveCriticalSection(&lock->lk); LeaveCriticalSection(&lock->lk);
LeaveCriticalSection(&lock->wlk); LeaveCriticalSection(&lock->wlk);
return TRUE; return TRUE;
} }
} }
lock->readers++; lock->readers++;
rc->count++;
LeaveCriticalSection(&lock->lk); LeaveCriticalSection(&lock->lk);
return TRUE; return TRUE;
} }
...@@ -54,9 +90,16 @@ BOOL ...@@ -54,9 +90,16 @@ BOOL
rwlock_tryrdlock(rwlock_t *lock) rwlock_tryrdlock(rwlock_t *lock)
{ {
BOOL ret = FALSE; BOOL ret = FALSE;
struct rwlock_reader_thread *rc;
EnterCriticalSection(&lock->lk); EnterCriticalSection(&lock->lk);
rc = find_self(lock, NULL);
if (rc == NULL) {
LeaveCriticalSection(&lock->lk);
return FALSE;
}
if (lock->writers == 0 && lock->writers_waiting == 0) { if (lock->writers == 0 && lock->writers_waiting == 0) {
rc->count++;
lock->readers++; lock->readers++;
ret = TRUE; ret = TRUE;
} }
...@@ -109,6 +152,9 @@ BOOL ...@@ -109,6 +152,9 @@ BOOL
rwlock_unlock(rwlock_t *lock) rwlock_unlock(rwlock_t *lock)
{ {
BOOL ret = FALSE; BOOL ret = FALSE;
struct rwlock_reader_thread *rc;
struct rwlock_reader_thread **prev;
EnterCriticalSection(&lock->lk); EnterCriticalSection(&lock->lk);
if (lock->writers) { if (lock->writers) {
if (lock->writer == GetCurrentThreadId()) { if (lock->writer == GetCurrentThreadId()) {
...@@ -121,12 +167,36 @@ rwlock_unlock(rwlock_t *lock) ...@@ -121,12 +167,36 @@ rwlock_unlock(rwlock_t *lock)
return FALSE; return FALSE;
} }
if (lock->readers) { if (lock->readers) {
lock->readers--; rc = find_self(lock, NULL);
return TRUE; if (rc && rc->count) {
rc->count--;
lock->readers--;
if (rc->count == 0) {
*prev = rc->next;
free(rc);
}
LeaveCriticalSection(&lock->lk);
return TRUE;
}
} }
LeaveCriticalSection(&lock->lk);
return FALSE; return FALSE;
} }
BOOL
rwlock_destory(rwlock_t *lock)
{
EnterCriticalSection(&lock->lk);
if (lock->readers || lock->writers || lock->writers_waiting || lock->rthreads) {
LeaveCriticalSection(&lock->lk);
return FALSE;
}
LeaveCriticalSection(&lock->lk);
DeleteCriticalSection(&lock->lk);
DeleteCriticalSection(&lock->wlk);
return TRUE;
}
#elif defined(__unix__) #elif defined(__unix__)
// All macros... // All macros...
......
...@@ -12,6 +12,7 @@ typedef pthread_rwlock_t rwlock_t; ...@@ -12,6 +12,7 @@ typedef pthread_rwlock_t rwlock_t;
#define rwlock_wrlock(lock) (pthread_rwlock_wrlock(lock) == 0) #define rwlock_wrlock(lock) (pthread_rwlock_wrlock(lock) == 0)
#define rwlock_trywrlock(lock) (pthread_rwlock_trywrlock(lock) == 0) #define rwlock_trywrlock(lock) (pthread_rwlock_trywrlock(lock) == 0)
#define rwlock_unlock(lock) (pthread_rwlock_unlock(lock) == 0) #define rwlock_unlock(lock) (pthread_rwlock_unlock(lock) == 0)
#define rwlock_destroy(lock) (pthread_rwlock_destroy(lock) == 0)
#elif defined(__BORLANDC__) #elif defined(__BORLANDC__)
...@@ -22,6 +23,12 @@ typedef pthread_rwlock_t rwlock_t; ...@@ -22,6 +23,12 @@ typedef pthread_rwlock_t rwlock_t;
#include "gen_defs.h" // For windows.h and BOOL!! :( #include "gen_defs.h" // For windows.h and BOOL!! :(
#include "threadwrap.h" #include "threadwrap.h"
struct rwlock_reader_thread {
struct rwlock_reader_thread *next;
DWORD id;
unsigned count;
};
typedef struct { typedef struct {
CRITICAL_SECTION lk; // Protects access to all elements CRITICAL_SECTION lk; // Protects access to all elements
CRITICAL_SECTION wlk; // Locked by an active writer CRITICAL_SECTION wlk; // Locked by an active writer
...@@ -29,6 +36,7 @@ typedef struct { ...@@ -29,6 +36,7 @@ typedef struct {
unsigned writers; unsigned writers;
unsigned writers_waiting; unsigned writers_waiting;
DWORD writer; DWORD writer;
struct rwlock_reader_thread *rthreads;
} rwlock_t; } rwlock_t;
BOOL rwlock_init(rwlock_t *lock); BOOL rwlock_init(rwlock_t *lock);
...@@ -37,6 +45,7 @@ BOOL rwlock_tryrdlock(rwlock_t *lock); ...@@ -37,6 +45,7 @@ BOOL rwlock_tryrdlock(rwlock_t *lock);
BOOL rwlock_wrlock(rwlock_t *lock); BOOL rwlock_wrlock(rwlock_t *lock);
BOOL rwlock_trywrlock(rwlock_t *lock); BOOL rwlock_trywrlock(rwlock_t *lock);
BOOL rwlock_unlock(rwlock_t *lock); BOOL rwlock_unlock(rwlock_t *lock);
BOOL rwlock_destory(rwlock_t *lock);
#else #else
#error Not implemented #error Not implemented
......
...@@ -79,6 +79,9 @@ int main() ...@@ -79,6 +79,9 @@ int main()
continue; continue;
} }
rwlock_wrlock_thread(&lock); rwlock_wrlock_thread(&lock);
if (!rwlock_destroy(&lock)) {
printf("Unable to destroy rwlock\n");
}
} while(0); } while(0);
for(i=0;i<3;i++) { for(i=0;i<3;i++) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment