source: rtems-libbsd/rtemsbsd/rtems/rtems-bsd-rwlock.c @ 0b1be9f

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 0b1be9f was 0b1be9f, checked in by Sebastian Huber <sebastian.huber@…>, on 10/24/13 at 15:37:50

RWLOCK(9): Use RTEMS mutex to support recursion

Support for recursive RWLOCK(9) is mandatory otherwise dead-lock happens
in the TCP protocol layer.

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_bsd_rtems
5 *
6 * @brief TODO.
7 */
8
9/*
10 * Copyright (c) 2011 OPTI Medical.  All rights reserved.
11 *
12 *  OPTI Medical
13 *  235 Hembree Park Drive
14 *  Roswell, GA 30076
15 *  USA
16 *  <kevin.kirspel@optimedical.com>
17 *
18 * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
19 *
20 *  embedded brains GmbH
21 *  Dornierstr. 4
22 *  82178 Puchheim
23 *  Germany
24 *  <rtems@embedded-brains.de>
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 *    notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 *    notice, this list of conditions and the following disclaimer in the
33 *    documentation and/or other materials provided with the distribution.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 * SUCH DAMAGE.
46 */
47
48#include <machine/rtems-bsd-config.h>
49#include <machine/rtems-bsd-thread.h>
50#include <machine/rtems-bsd-support.h>
51
52#include <rtems.h>
53
54#include <rtems/bsd/sys/param.h>
55#include <rtems/bsd/sys/types.h>
56#include <sys/systm.h>
57#include <rtems/bsd/sys/lock.h>
58#include <sys/rwlock.h>
59#include <sys/mutex.h>
60
61#ifndef INVARIANTS
62#define _rw_assert(rw, what, file, line)
63#endif
64
65static void assert_rw(struct lock_object *lock, int what);
66static void lock_rw(struct lock_object *lock, int how);
67#ifdef KDTRACE_HOOKS
68static int  owner_rw(struct lock_object *lock, struct thread **owner);
69#endif
70static int  unlock_rw(struct lock_object *lock);
71
72struct lock_class lock_class_rw = {
73  .lc_name = "rw",
74  .lc_flags = LC_SLEEPLOCK | LC_RECURSABLE | LC_UPGRADABLE,
75  .lc_assert = assert_rw,
76#ifdef DDB
77  .lc_ddb_show = db_show_rwlock,
78#endif
79  .lc_lock = lock_rw,
80  .lc_unlock = unlock_rw,
81#ifdef KDTRACE_HOOKS
82  .lc_owner = owner_rw,
83#endif
84};
85
86RTEMS_CHAIN_DEFINE_EMPTY(rtems_bsd_rwlock_chain);
87
88void
89assert_rw(struct lock_object *lock, int what)
90{
91  rw_assert((struct rwlock *)lock, what);
92}
93
94void
95lock_rw(struct lock_object *lock, int how)
96{
97  struct rwlock *rw;
98
99  rw = (struct rwlock *)lock;
100  if (how)
101    rw_wlock(rw);
102  else
103    rw_rlock(rw);
104}
105
106int
107unlock_rw(struct lock_object *lock)
108{
109  struct rwlock *rw;
110
111  rw = (struct rwlock *)lock;
112  rw_assert(rw, RA_LOCKED | LA_NOTRECURSED);
113  if (rw->rw_lock & RW_LOCK_READ) {
114    rw_runlock(rw);
115    return (0);
116  } else {
117    rw_wunlock(rw);
118    return (1);
119  }
120}
121
122#ifdef KDTRACE_HOOKS
123int
124owner_rw(struct lock_object *lock, struct thread **owner)
125{
126  struct rwlock *rw = (struct rwlock *)lock;
127  uintptr_t x = rw->rw_lock;
128
129  *owner = rw_wowner(rw);
130  return ((x & RW_LOCK_READ) != 0 ?  (RW_READERS(x) != 0) :
131      (*owner != NULL));
132}
133#endif
134
135void
136rw_init_flags(struct rwlock *rw, const char *name, int opts)
137{
138  struct lock_class *class;
139  int i;
140  rtems_status_code sc;
141  rtems_id id;
142  rtems_attribute attr = RTEMS_LOCAL | RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY;
143
144  if ((opts & RW_RECURSE) != 0) {
145    /* FIXME */
146  }
147
148  class = &lock_class_rw;
149
150  /* Check for double-init and zero object. */
151  KASSERT(!lock_initalized(&rw->lock_object), ("lock \"%s\" %p already initialized", name, rw->lock_object));
152
153  /* Look up lock class to find its index. */
154  for (i = 0; i < LOCK_CLASS_MAX; i++)
155  {
156    if (lock_classes[i] == class)
157    {
158      rw->lock_object.lo_flags = i << LO_CLASSSHIFT;
159      break;
160    }
161  }
162  KASSERT(i < LOCK_CLASS_MAX, ("unknown lock class %p", class));
163
164  sc = rtems_semaphore_create(
165    rtems_build_name('_', '_', 'R', 'W'),
166    1,
167    attr,
168    BSD_TASK_PRIORITY_RESOURCE_OWNER,
169    &id
170  );
171  BSD_ASSERT_SC(sc);
172
173  rw->lock_object.lo_name = name;
174  rw->lock_object.lo_flags |= LO_INITIALIZED;
175  rw->lock_object.lo_id = id;
176
177  rtems_chain_append(&rtems_bsd_rwlock_chain, &rw->lock_object.lo_node);
178}
179
180void
181rw_destroy(struct rwlock *rw)
182{
183  mtx_destroy((struct mtx *) rw);
184}
185
186void
187rw_sysinit(void *arg)
188{
189  struct rw_args *args = arg;
190
191  rw_init(args->ra_rw, args->ra_desc);
192}
193
194void
195rw_sysinit_flags(void *arg)
196{
197  struct rw_args_flags *args = arg;
198
199  rw_init_flags(args->ra_rw, args->ra_desc, args->ra_flags);
200}
201
202int
203rw_wowned(struct rwlock *rw)
204{
205  return mtx_owned((struct mtx *) rw);
206}
207
208void
209_rw_wlock(struct rwlock *rw, const char *file, int line)
210{
211  _mtx_lock_flags((struct mtx *) rw, 0, file, line);
212}
213
214int
215_rw_try_wlock(struct rwlock *rw, const char *file, int line)
216{
217  return _mtx_trylock((struct mtx *) rw, 0, file, line);
218}
219
220void
221_rw_wunlock(struct rwlock *rw, const char *file, int line)
222{
223  _mtx_unlock_flags((struct mtx *) rw, 0, file, line);
224}
225
226void
227_rw_rlock(struct rwlock *rw, const char *file, int line)
228{
229  _mtx_lock_flags((struct mtx *) rw, 0, file, line);
230}
231
232int
233_rw_try_rlock(struct rwlock *rw, const char *file, int line)
234{
235  return _mtx_trylock((struct mtx *) rw, 0, file, line);
236}
237
238void
239_rw_runlock(struct rwlock *rw, const char *file, int line)
240{
241  _mtx_unlock_flags((struct mtx *) rw, 0, file, line);
242}
243
244int
245_rw_try_upgrade(struct rwlock *rw, const char *file, int line)
246{
247  return 1;
248}
249
250void
251_rw_downgrade(struct rwlock *rw, const char *file, int line)
252{
253  /* Nothing to do */
254}
255
256#ifdef INVARIANT_SUPPORT
257#ifndef INVARIANTS
258#undef _rw_assert
259#endif
260
261/*
262 * In the non-WITNESS case, rw_assert() can only detect that at least
263 * *some* thread owns an rlock, but it cannot guarantee that *this*
264 * thread owns an rlock.
265 */
266void
267_rw_assert(struct rwlock *rw, int what, const char *file, int line)
268{
269
270  if (panicstr != NULL)
271    return;
272  switch (what) {
273  case RA_LOCKED:
274  case RA_LOCKED | RA_RECURSED:
275  case RA_LOCKED | RA_NOTRECURSED:
276  case RA_RLOCKED:
277#ifdef WITNESS
278    witness_assert(&rw->lock_object, what, file, line);
279#else
280    /*
281     * If some other thread has a write lock or we have one
282     * and are asserting a read lock, fail.  Also, if no one
283     * has a lock at all, fail.
284     */
285    if (rw->rw_lock == RW_UNLOCKED ||
286        (!(rw->rw_lock & RW_LOCK_READ) && (what == RA_RLOCKED ||
287        rw_wowner(rw) != curthread)))
288      panic("Lock %s not %slocked @ %s:%d\n",
289          rw->lock_object.lo_name, (what == RA_RLOCKED) ?
290          "read " : "", file, line);
291
292    if (!(rw->rw_lock & RW_LOCK_READ)) {
293      if (rw_recursed(rw)) {
294        if (what & RA_NOTRECURSED)
295          panic("Lock %s recursed @ %s:%d\n",
296              rw->lock_object.lo_name, file,
297              line);
298      } else if (what & RA_RECURSED)
299        panic("Lock %s not recursed @ %s:%d\n",
300            rw->lock_object.lo_name, file, line);
301    }
302#endif
303    break;
304  case RA_WLOCKED:
305  case RA_WLOCKED | RA_RECURSED:
306  case RA_WLOCKED | RA_NOTRECURSED:
307    if (rw_wowner(rw) != curthread)
308      panic("Lock %s not exclusively locked @ %s:%d\n",
309          rw->lock_object.lo_name, file, line);
310    if (rw_recursed(rw)) {
311      if (what & RA_NOTRECURSED)
312        panic("Lock %s recursed @ %s:%d\n",
313            rw->lock_object.lo_name, file, line);
314    } else if (what & RA_RECURSED)
315      panic("Lock %s not recursed @ %s:%d\n",
316          rw->lock_object.lo_name, file, line);
317    break;
318  case RA_UNLOCKED:
319#ifdef WITNESS
320    witness_assert(&rw->lock_object, what, file, line);
321#else
322    /*
323     * If we hold a write lock fail.  We can't reliably check
324     * to see if we hold a read lock or not.
325     */
326    if (rw_wowner(rw) == curthread)
327      panic("Lock %s exclusively locked @ %s:%d\n",
328          rw->lock_object.lo_name, file, line);
329#endif
330    break;
331  default:
332    panic("Unknown rw lock assertion: %d @ %s:%d", what, file,
333        line);
334  }
335}
336#endif /* INVARIANT_SUPPORT */
Note: See TracBrowser for help on using the repository browser.