source: rtems-libbsd/rtemsbsd/rtems/rtems-bsd-rwlock.c @ 150d4d6

4.115-freebsd-12freebsd-9.3
Last change on this file since 150d4d6 was 150d4d6, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 24, 2013 at 9:11:32 AM

Move content to new <machine/rtems-bsd-support.h>

  • Property mode set to 100644
File size: 9.6 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 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 *    notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 *    notice, this list of conditions and the following disclaimer in the
25 *    documentation and/or other materials provided with the distribution.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39
40#include <machine/rtems-bsd-config.h>
41#include <machine/rtems-bsd-support.h>
42
43#include <rtems/score/objectimpl.h>
44#include <rtems/posix/rwlockimpl.h>
45
46#include <rtems/bsd/sys/param.h>
47#include <rtems/bsd/sys/types.h>
48#include <sys/systm.h>
49#include <rtems/bsd/sys/lock.h>
50#include <sys/rwlock.h>
51
52#ifndef INVARIANTS
53#define _rw_assert(rw, what, file, line)
54#endif
55
56static void assert_rw(struct lock_object *lock, int what);
57static void lock_rw(struct lock_object *lock, int how);
58#ifdef KDTRACE_HOOKS
59static int  owner_rw(struct lock_object *lock, struct thread **owner);
60#endif
61static int  unlock_rw(struct lock_object *lock);
62
63struct lock_class lock_class_rw = {
64  .lc_name = "rw",
65  .lc_flags = LC_SLEEPLOCK | LC_RECURSABLE | LC_UPGRADABLE,
66  .lc_assert = assert_rw,
67#ifdef DDB
68  .lc_ddb_show = db_show_rwlock,
69#endif
70  .lc_lock = lock_rw,
71  .lc_unlock = unlock_rw,
72#ifdef KDTRACE_HOOKS
73  .lc_owner = owner_rw,
74#endif
75};
76
77RTEMS_CHAIN_DEFINE_EMPTY(rtems_bsd_rwlock_chain);
78
79void
80assert_rw(struct lock_object *lock, int what)
81{
82  rw_assert((struct rwlock *)lock, what);
83}
84
85void
86lock_rw(struct lock_object *lock, int how)
87{
88  struct rwlock *rw;
89
90  rw = (struct rwlock *)lock;
91  if (how)
92    rw_wlock(rw);
93  else
94    rw_rlock(rw);
95}
96
97int
98unlock_rw(struct lock_object *lock)
99{
100  struct rwlock *rw;
101
102  rw = (struct rwlock *)lock;
103  rw_assert(rw, RA_LOCKED | LA_NOTRECURSED);
104  if (rw->rw_lock & RW_LOCK_READ) {
105    rw_runlock(rw);
106    return (0);
107  } else {
108    rw_wunlock(rw);
109    return (1);
110  }
111}
112
113#ifdef KDTRACE_HOOKS
114int
115owner_rw(struct lock_object *lock, struct thread **owner)
116{
117  struct rwlock *rw = (struct rwlock *)lock;
118  uintptr_t x = rw->rw_lock;
119
120  *owner = rw_wowner(rw);
121  return ((x & RW_LOCK_READ) != 0 ?  (RW_READERS(x) != 0) :
122      (*owner != NULL));
123}
124#endif
125
126void
127rw_init_flags(struct rwlock *rw, const char *name, int opts)
128{
129  struct lock_class *class;
130  int i;
131  pthread_rwlock_t lock;
132  int iret;
133
134  if ((opts & RW_RECURSE) != 0) {
135    /* FIXME */
136  }
137
138  class = &lock_class_rw;
139
140  /* Check for double-init and zero object. */
141  KASSERT(!lock_initalized(&rw->lock_object), ("lock \"%s\" %p already initialized", name, rw->lock_object));
142
143  /* Look up lock class to find its index. */
144  for (i = 0; i < LOCK_CLASS_MAX; i++)
145  {
146    if (lock_classes[i] == class)
147    {
148      rw->lock_object.lo_flags = i << LO_CLASSSHIFT;
149      break;
150    }
151  }
152  KASSERT(i < LOCK_CLASS_MAX, ("unknown lock class %p", class));
153
154  iret = pthread_rwlock_init( &lock, NULL );
155  BSD_ASSERT( iret == 0 );
156
157  rw->lock_object.lo_name = name;
158  rw->lock_object.lo_flags |= LO_INITIALIZED;
159  rw->lock_object.lo_id = lock;
160
161  rtems_chain_append(&rtems_bsd_rwlock_chain, &rw->lock_object.lo_node);
162}
163
164void
165rw_destroy(struct rwlock *rw)
166{
167  int iret;
168  pthread_rwlock_destroy( rw->lock_object.lo_id );
169  BSD_ASSERT( iret == 0 );
170  rtems_chain_extract( &rw->lock_object.lo_node );
171  rw->lock_object.lo_id = 0;
172  rw->lock_object.lo_flags &= ~LO_INITIALIZED;
173}
174
175void
176rw_sysinit(void *arg)
177{
178  struct rw_args *args = arg;
179
180  rw_init(args->ra_rw, args->ra_desc);
181}
182
183void
184rw_sysinit_flags(void *arg)
185{
186  struct rw_args_flags *args = arg;
187
188  rw_init_flags(args->ra_rw, args->ra_desc, args->ra_flags);
189}
190
191/* XXX add pthread_rwlock_is_wlocked_np( id, &wlocked )
192 * XXX    returns 0 or -1 w/error
193 * XXX    wlocked = 1 if write locked
194 * XXX
195/* XXX add pthread_rwlock_is_rlocked_np( id, &wlocked )
196 * XXX    similar behavior
197 * XXX probably want to add "unlocked" state to RTEMS SuperCore rwlock
198 * XXX
199 * XXX Rationale: This violates the API layering BADLY!!!!!
200 * XXX Consider: Adding pthread_np.h to hold np methods like FreeBSD
201 * XXX           This would avoid polluting pthread.h
202 */
203int
204rw_wowned(struct rwlock *rw)
205{
206  int                   is_locked_for_write = 0;
207  Objects_Locations     location;
208  POSIX_RWLock_Control *the_rwlock;
209
210  the_rwlock = _POSIX_RWLock_Get(&rw->lock_object.lo_id, &location);
211  switch ( location ) {
212
213    case OBJECTS_LOCAL:
214      if (the_rwlock->RWLock.current_state == CORE_RWLOCK_LOCKED_FOR_WRITING)
215        is_locked_for_write = 1;
216      _Thread_Enable_dispatch();
217      return is_locked_for_write;
218
219#if defined(RTEMS_MULTIPROCESSING)
220    case OBJECTS_REMOTE:
221#endif
222    case OBJECTS_ERROR:
223      break;
224  }
225  _Thread_Enable_dispatch();
226
227  BSD_PANIC("unexpected semaphore location or attributes");
228}
229
230void
231_rw_wlock(struct rwlock *rw, const char *file, int line)
232{
233  int iret;
234
235  iret = pthread_rwlock_wrlock( &rw->lock_object.lo_id );
236  BSD_ASSERT( iret == 0 );
237
238  return 0;
239}
240
241int
242_rw_try_wlock(struct rwlock *rw, const char *file, int line)
243{
244  int iret;
245
246  iret = pthread_rwlock_trywrlock( &rw->lock_object.lo_id );
247  if (iret == 0) {
248    return 1;
249  } else {
250    return 0;
251  }
252}
253
254void
255_rw_wunlock(struct rwlock *rw, const char *file, int line)
256{
257  int iret;
258
259  iret = pthread_rwlock_unlock( &rw->lock_object.lo_id );
260  BSD_ASSERT( iret == 0 );
261}
262
263void
264_rw_rlock(struct rwlock *rw, const char *file, int line)
265{
266  int iret;
267
268  iret = pthread_rwlock_rdlock( &rw->lock_object.lo_id );
269  BSD_ASSERT( iret == 0 );
270}
271
272int
273_rw_try_rlock(struct rwlock *rw, const char *file, int line)
274{
275  int iret;
276
277  iret = pthread_rwlock_tryrdlock( &rw->lock_object.lo_id );
278  if (iret == 0) {
279    return 1;
280  } else {
281    return 0;
282  }
283}
284
285void
286_rw_runlock(struct rwlock *rw, const char *file, int line)
287{
288  int iret;
289
290  iret = pthread_rwlock_unlock( &rw->lock_object.lo_id );
291  BSD_ASSERT( iret == 0 );
292}
293
294/*
295 * Attempt to do a non-blocking upgrade from a read lock to a write
296 * lock.  This will only succeed if this thread holds a single read
297 * lock.  Returns true if the upgrade succeeded and false otherwise.
298 */
299int
300_rw_try_upgrade(struct rwlock *rw, const char *file, int line)
301{
302  return 0; /* XXX */
303}
304
305/*
306 * Downgrade a write lock into a single read lock.
307 */
308void
309_rw_downgrade(struct rwlock *rw, const char *file, int line)
310{
311  /* XXX */ 
312}
313
314#ifdef INVARIANT_SUPPORT
315#ifndef INVARIANTS
316#undef _rw_assert
317#endif
318
319/*
320 * In the non-WITNESS case, rw_assert() can only detect that at least
321 * *some* thread owns an rlock, but it cannot guarantee that *this*
322 * thread owns an rlock.
323 */
324void
325_rw_assert(struct rwlock *rw, int what, const char *file, int line)
326{
327
328  if (panicstr != NULL)
329    return;
330  switch (what) {
331  case RA_LOCKED:
332  case RA_LOCKED | RA_RECURSED:
333  case RA_LOCKED | RA_NOTRECURSED:
334  case RA_RLOCKED:
335#ifdef WITNESS
336    witness_assert(&rw->lock_object, what, file, line);
337#else
338    /*
339     * If some other thread has a write lock or we have one
340     * and are asserting a read lock, fail.  Also, if no one
341     * has a lock at all, fail.
342     */
343    if (rw->rw_lock == RW_UNLOCKED ||
344        (!(rw->rw_lock & RW_LOCK_READ) && (what == RA_RLOCKED ||
345        rw_wowner(rw) != curthread)))
346      panic("Lock %s not %slocked @ %s:%d\n",
347          rw->lock_object.lo_name, (what == RA_RLOCKED) ?
348          "read " : "", file, line);
349
350    if (!(rw->rw_lock & RW_LOCK_READ)) {
351      if (rw_recursed(rw)) {
352        if (what & RA_NOTRECURSED)
353          panic("Lock %s recursed @ %s:%d\n",
354              rw->lock_object.lo_name, file,
355              line);
356      } else if (what & RA_RECURSED)
357        panic("Lock %s not recursed @ %s:%d\n",
358            rw->lock_object.lo_name, file, line);
359    }
360#endif
361    break;
362  case RA_WLOCKED:
363  case RA_WLOCKED | RA_RECURSED:
364  case RA_WLOCKED | RA_NOTRECURSED:
365    if (rw_wowner(rw) != curthread)
366      panic("Lock %s not exclusively locked @ %s:%d\n",
367          rw->lock_object.lo_name, file, line);
368    if (rw_recursed(rw)) {
369      if (what & RA_NOTRECURSED)
370        panic("Lock %s recursed @ %s:%d\n",
371            rw->lock_object.lo_name, file, line);
372    } else if (what & RA_RECURSED)
373      panic("Lock %s not recursed @ %s:%d\n",
374          rw->lock_object.lo_name, file, line);
375    break;
376  case RA_UNLOCKED:
377#ifdef WITNESS
378    witness_assert(&rw->lock_object, what, file, line);
379#else
380    /*
381     * If we hold a write lock fail.  We can't reliably check
382     * to see if we hold a read lock or not.
383     */
384    if (rw_wowner(rw) == curthread)
385      panic("Lock %s exclusively locked @ %s:%d\n",
386          rw->lock_object.lo_name, file, line);
387#endif
388    break;
389  default:
390    panic("Unknown rw lock assertion: %d @ %s:%d", what, file,
391        line);
392  }
393}
394#endif /* INVARIANT_SUPPORT */
Note: See TracBrowser for help on using the repository browser.