pthread_rwlock.h
6.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
* Copyright (C) 2014 René Kijewski <rene.kijewski@fu-berlin.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pthread
* @{
* @file
* @brief Implementation of a fair, POSIX conforming reader/writer lock.
* @note Do not include this header file directly, but pthread.h.
*/
#ifndef PTHREAD_RWLOCK_H
#define PTHREAD_RWLOCK_H
#include "priority_queue.h"
#include "thread.h"
#include <errno.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief A fair reader writer lock.
* @details The implementation ensures that readers and writers of the same priority
* won't starve each other.
* E.g. no new readers will get into the critical section
* if a writer of the same or a higher priority already waits for the lock.
*/
typedef struct
{
/**
* @brief The current amount of reader inside the critical section.
* @details
* * `== 0`: no thread is in the critical section.
* * `> 0`: the number of readers currently in the critical section.
* * `< 0`: a writer is currently in the critical section.
*/
int readers;
/**
* @brief Queue of waiting threads.
*/
priority_queue_t queue;
/**
* @brief Provides mutual exclusion on reading and writing on the structure.
*/
mutex_t mutex;
} pthread_rwlock_t;
/**
* @brief Internal structure that stores one waiting thread.
*/
typedef struct {
bool is_writer; /**< `false`: reader; `true`: writer */
thread_t *thread; /**< waiting thread */
priority_queue_node_t qnode; /**< Node to store in `pthread_rwlock_t::queue`. */
bool continue_; /**< This is not a spurious wakeup. */
} __pthread_rwlock_waiter_node_t;
/**
* @brief Initialize a reader/writer lock.
* @details A zeroed out datum is initialized.
* @param[in,out] rwlock Lock to initialize.
* @param[in] attr Unused.
* @returns `0` on success.
* `EINVAL` if `rwlock == NULL`.
*/
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
/**
* @brief Destroy a reader/writer lock.
* @details This is a no-op.
* Destroying a reader/writer lock while a thread holds it, or
* there are threads waiting for it causes undefined behavior.
* Datum must be reinitialized before using it again.
* @param[in] rwlock Lock to destroy.
* @returns `0` on success.
* `EINVAL` if `rwlock == NULL`.
* `EBUSY` if the lock was in use.
*/
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
/**
* @brief Lock a reader/writer lock for reading.
* @details This function may block.
* @param[in] rwlock Lock to acquire for reading.
* @returns `0` if the lock could be acquired.
* `EINVAL` if `rwlock == NULL`.
*/
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
/**
* @brief Try to lock a reader/writer lock for reader.
* @details This function won't block.
* @param[in] rwlock Lock to acquire for reading.
* @returns `0` if the lock could be acquired.
* `EBUSY` if acquiring the lock cannot be done without blocking.
* `EINVAL` if `rwlock == NULL`.
*/
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
/**
* @brief Try to acquire a read lock in a given timeframe
* @param[in] rwlock Lock to acquire for reading.
* @param[in] abstime Maximum timestamp when to wakeup, absolute.
* @returns `0` if the lock could be acquired.
* `EDEADLK` if the lock could not be acquired in the given timeframe.
* `EINVAL` if `rwlock == NULL`.
*/
int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, const struct timespec *abstime);
/**
* @brief Lock a reader/writer lock for writing.
* @details This function may block.
* @param[in] rwlock Lock to acquire for writing.
* @returns `0` if the lock could be acquired.
* `EINVAL` if `rwlock == NULL`.
*/
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
/**
* @brief Try to lock a reader/writer lock for writing.
* @details This function won't block.
* @param[in] rwlock Lock to acquire for writing.
* @returns `0` if the lock could be acquired.
* `EBUSY` if acquiring the lock cannot be done without blocking.
* `EINVAL` if `rwlock == NULL`.
*/
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
/**
* @brief Try to acquire a write lock in a given timeframe
* @param[in] rwlock Lock to acquire for writing.
* @param[in] abstime Maximum timestamp when to wakeup, absolute.
* @returns `0` if the lock could be acquired.
* `EDEADLK` if the lock could not be acquired in the given timeframe.
* `EINVAL` if `rwlock == NULL`.
*/
int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *abstime);
/**
* @brief Unlock the reader/writer lock.
* @details Must only be used if the lock is currently held.
* You may release the lock out of another thread, but the *lock*, *operate*, *unlock* logic must not be broken.
* @param[in] rwlock Lock to release
* @returns `0` on success.
* `EPERM` if the lock was not held for any operation.
* `EINVAL` if `rwlock == NULL`.
*/
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
/**
* @brief Internal function to determine of the lock can be acquired for reading.
* @param[in] rwlock Lock to query.
* @returns `false` if locking for reading is possible without blocking.
*/
bool __pthread_rwlock_blocked_readingly(const pthread_rwlock_t *rwlock);
/**
* @brief Internal function to determine of the lock can be acquired for writing.
* @param[in] rwlock Lock to query.
* @returns `false` if locking for writing is possible without blocking.
*/
bool __pthread_rwlock_blocked_writingly(const pthread_rwlock_t *rwlock);
#ifdef __cplusplus
}
#endif
#endif /* PTHREAD_RWLOCK_H */
/**
* @}
*/