Blame view

RIOT/sys/posix/pthread/include/pthread_rwlock.h 6.44 KB
a752c7ab   elopes   add first test an...
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 */
  
  /**
   * @}
   */