From 81decf740770965e73d8bcb4c73d20115eb5beb1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= <jerome.duval@gmail.com>
Date: Mon, 24 Jul 2017 21:09:55 +0200
Subject: [PATCH] pthread_rwlock: use a mutex for process-private locks.
* instead of a benaphore.
* define PTHREAD_RWLOCK_INITIALIZER.
* adjust Init(), Destroy(), StructureLock() and StructureUnlock().
---
headers/posix/pthread.h | 2 ++
headers/posix/sys/types.h | 10 +++---
.../libroot/posix/pthread/pthread_rwlock.cpp | 40 +++++++++++++++-------
3 files changed, 34 insertions(+), 18 deletions(-)
diff --git a/headers/posix/pthread.h b/headers/posix/pthread.h
index 489aace..feaf8e3 100644
a
|
b
|
extern "C" {
|
80 | 80 | { PTHREAD_MUTEX_RECURSIVE, 0, -42, -1, 0 } |
81 | 81 | #define PTHREAD_COND_INITIALIZER \ |
82 | 82 | { 0, -42, NULL, 0, 0 } |
| 83 | #define PTHREAD_RWLOCK_INITIALIZER \ |
| 84 | { 0, -1, {{0}} } |
83 | 85 | |
84 | 86 | /* mutex functions */ |
85 | 87 | extern int pthread_mutex_destroy(pthread_mutex_t *mutex); |
diff --git a/headers/posix/sys/types.h b/headers/posix/sys/types.h
index b09aba5..64d497e 100644
a
|
b
|
struct _pthread_rwlock {
|
105 | 105 | __haiku_std_int32 owner; |
106 | 106 | union { |
107 | 107 | struct { |
108 | | __haiku_std_int32 sem; |
109 | | } shared; |
110 | | struct { |
111 | | __haiku_std_int32 lock_sem; |
112 | | __haiku_std_int32 lock_count; |
| 108 | __haiku_std_int32 mutex; |
| 109 | __haiku_std_int32 unused; |
113 | 110 | __haiku_std_int32 reader_count; |
114 | 111 | __haiku_std_int32 writer_count; |
115 | 112 | void* waiters[2]; |
116 | 113 | } local; |
| 114 | struct { |
| 115 | __haiku_std_int32 sem; |
| 116 | } shared; |
117 | 117 | } u; |
118 | 118 | }; |
119 | 119 | |
diff --git a/src/system/libroot/posix/pthread/pthread_rwlock.cpp b/src/system/libroot/posix/pthread/pthread_rwlock.cpp
index 65e83be..b2470ae 100644
a
|
b
|
|
12 | 12 | #include <AutoLocker.h> |
13 | 13 | #include <libroot_lock.h> |
14 | 14 | #include <syscalls.h> |
| 15 | #include <user_mutex_defs.h> |
15 | 16 | #include <user_thread.h> |
16 | 17 | #include <util/DoublyLinkedList.h> |
17 | 18 | |
18 | 19 | #include "pthread_private.h" |
19 | 20 | |
20 | | |
21 | 21 | #define MAX_READER_COUNT 1000000 |
22 | 22 | |
23 | 23 | #define RWLOCK_FLAG_SHARED 0x01 |
… |
… |
struct SharedRWLock {
|
93 | 93 | struct LocalRWLock { |
94 | 94 | uint32_t flags; |
95 | 95 | int32_t owner; |
96 | | int32_t lock_sem; |
97 | | int32_t lock_count; |
| 96 | int32_t mutex; |
| 97 | int32_t unused; |
98 | 98 | int32_t reader_count; |
99 | 99 | int32_t writer_count; |
100 | 100 | // Note, that reader_count and writer_count are not used the same way. |
… |
… |
struct LocalRWLock {
|
106 | 106 | { |
107 | 107 | flags = 0; |
108 | 108 | owner = -1; |
109 | | lock_sem = create_sem(0, "pthread rwlock"); |
110 | | lock_count = 1; |
| 109 | mutex = 0; |
111 | 110 | reader_count = 0; |
112 | 111 | writer_count = 0; |
113 | 112 | new(&waiters) WaiterList; |
114 | 113 | |
115 | | return lock_sem >= 0 ? B_OK : EAGAIN; |
| 114 | return B_OK; |
116 | 115 | } |
117 | 116 | |
118 | 117 | status_t Destroy() |
119 | 118 | { |
120 | | if (lock_sem < 0) |
121 | | return B_BAD_VALUE; |
122 | | return delete_sem(lock_sem) == B_OK ? B_OK : B_BAD_VALUE; |
| 119 | Locker locker(this); |
| 120 | if (reader_count > 0 || waiters.Head() != NULL || writer_count > 0) |
| 121 | return EBUSY; |
| 122 | return B_OK; |
123 | 123 | } |
124 | 124 | |
125 | 125 | bool StructureLock() |
126 | 126 | { |
127 | | if (atomic_add((int32*)&lock_count, -1) <= 0) |
128 | | acquire_sem(lock_sem); |
| 127 | // Enter critical region: lock the mutex |
| 128 | int32 status = atomic_or((int32*)&mutex, B_USER_MUTEX_LOCKED); |
| 129 | |
| 130 | // If already locked, call the kernel |
| 131 | if ((status & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) != 0) { |
| 132 | do { |
| 133 | status = _kern_mutex_lock((int32*)&mutex, NULL, 0, 0); |
| 134 | } while (status == B_INTERRUPTED); |
| 135 | |
| 136 | if (status != B_OK) |
| 137 | return false; |
| 138 | } |
129 | 139 | return true; |
130 | 140 | } |
131 | 141 | |
132 | 142 | void StructureUnlock() |
133 | 143 | { |
134 | | if (atomic_add((int32*)&lock_count, 1) < 0) |
135 | | release_sem(lock_sem); |
| 144 | // Exit critical region: unlock the mutex |
| 145 | int32 status = atomic_and((int32*)&mutex, |
| 146 | ~(int32)B_USER_MUTEX_LOCKED); |
| 147 | |
| 148 | if ((status & B_USER_MUTEX_WAITING) != 0) |
| 149 | _kern_mutex_unlock((int32*)&mutex, 0); |
136 | 150 | } |
137 | 151 | |
138 | 152 | status_t ReadLock(bigtime_t timeout) |