1d54cfbdroberto/*
2d54cfbdroberto * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
3d54cfbdroberto * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
4d54cfbdroberto *
5d54cfbdroberto * Permission to use, copy, modify, and/or distribute this software for any
6d54cfbdroberto * purpose with or without fee is hereby granted, provided that the above
7d54cfbdroberto * copyright notice and this permission notice appear in all copies.
8d54cfbdroberto *
9d54cfbdroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10d54cfbdroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11d54cfbdroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12d54cfbdroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13d54cfbdroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14d54cfbdroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15d54cfbdroberto * PERFORMANCE OF THIS SOFTWARE.
16d54cfbdroberto */
17d54cfbdroberto
18d54cfbdroberto/* $Id: rwlock.h,v 1.28 2007/06/19 23:47:18 tbox Exp $ */
19d54cfbdroberto
20d54cfbdroberto#ifndef ISC_RWLOCK_H
21d54cfbdroberto#define ISC_RWLOCK_H 1
22d54cfbdroberto
23d54cfbdroberto/*! \file isc/rwlock.h */
24d54cfbdroberto
25d54cfbdroberto#include <isc/condition.h>
26d54cfbdroberto#include <isc/lang.h>
27d54cfbdroberto#include <isc/platform.h>
28d54cfbdroberto#include <isc/types.h>
29d54cfbdroberto
30d54cfbdrobertoISC_LANG_BEGINDECLS
31d54cfbdroberto
32d54cfbdrobertotypedef enum {
33d54cfbdroberto	isc_rwlocktype_none = 0,
34d54cfbdroberto	isc_rwlocktype_read,
35d54cfbdroberto	isc_rwlocktype_write
36d54cfbdroberto} isc_rwlocktype_t;
37d54cfbdroberto
38d54cfbdroberto#ifdef ISC_PLATFORM_USETHREADS
39d54cfbdroberto#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
40d54cfbdroberto#define ISC_RWLOCK_USEATOMIC 1
41d54cfbdroberto#endif
42d54cfbdroberto
43d54cfbdrobertostruct isc_rwlock {
44d54cfbdroberto	/* Unlocked. */
45d54cfbdroberto	unsigned int		magic;
46d54cfbdroberto	isc_mutex_t		lock;
47d54cfbdroberto
48d54cfbdroberto#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
49d54cfbdroberto	/*
50d54cfbdroberto	 * When some atomic instructions with hardware assistance are
51d54cfbdroberto	 * available, rwlock will use those so that concurrent readers do not
52d54cfbdroberto	 * interfere with each other through mutex as long as no writers
53d54cfbdroberto	 * appear, massively reducing the lock overhead in the typical case.
54d54cfbdroberto	 *
55d54cfbdroberto	 * The basic algorithm of this approach is the "simple
56d54cfbdroberto	 * writer-preference lock" shown in the following URL:
57d54cfbdroberto	 * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html
58d54cfbdroberto	 * but our implementation does not rely on the spin lock unlike the
59d54cfbdroberto	 * original algorithm to be more portable as a user space application.
60d54cfbdroberto	 */
61d54cfbdroberto
62d54cfbdroberto	/* Read or modified atomically. */
63d54cfbdroberto	isc_int32_t		write_requests;
64d54cfbdroberto	isc_int32_t		write_completions;
65d54cfbdroberto	isc_int32_t		cnt_and_flag;
66d54cfbdroberto
67d54cfbdroberto	/* Locked by lock. */
68d54cfbdroberto	isc_condition_t		readable;
69d54cfbdroberto	isc_condition_t		writeable;
70d54cfbdroberto	unsigned int		readers_waiting;
71d54cfbdroberto
72d54cfbdroberto	/* Locked by rwlock itself. */
73d54cfbdroberto	unsigned int		write_granted;
74d54cfbdroberto
75d54cfbdroberto	/* Unlocked. */
76d54cfbdroberto	unsigned int		write_quota;
77d54cfbdroberto
78d54cfbdroberto#else  /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
79d54cfbdroberto
80d54cfbdroberto	/*%< Locked by lock. */
81d54cfbdroberto	isc_condition_t		readable;
82d54cfbdroberto	isc_condition_t		writeable;
83d54cfbdroberto	isc_rwlocktype_t	type;
84d54cfbdroberto
85d54cfbdroberto	/*% The number of threads that have the lock. */
86d54cfbdroberto	unsigned int		active;
87d54cfbdroberto
88d54cfbdroberto	/*%
89d54cfbdroberto	 * The number of lock grants made since the lock was last switched
90d54cfbdroberto	 * from reading to writing or vice versa; used in determining
91d54cfbdroberto	 * when the quota is reached and it is time to switch.
92d54cfbdroberto	 */
93d54cfbdroberto	unsigned int		granted;
94d54cfbdroberto
95d54cfbdroberto	unsigned int		readers_waiting;
96d54cfbdroberto	unsigned int		writers_waiting;
97d54cfbdroberto	unsigned int		read_quota;
98d54cfbdroberto	unsigned int		write_quota;
99d54cfbdroberto	isc_rwlocktype_t	original;
100d54cfbdroberto#endif  /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
101d54cfbdroberto};
102d54cfbdroberto#else /* ISC_PLATFORM_USETHREADS */
103d54cfbdrobertostruct isc_rwlock {
104d54cfbdroberto	unsigned int		magic;
105d54cfbdroberto	isc_rwlocktype_t	type;
106d54cfbdroberto	unsigned int		active;
107d54cfbdroberto};
108d54cfbdroberto#endif /* ISC_PLATFORM_USETHREADS */
109d54cfbdroberto
110d54cfbdroberto
111d54cfbdrobertoisc_result_t
112d54cfbdrobertoisc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
113d54cfbdroberto		unsigned int write_quota);
114d54cfbdroberto
115d54cfbdrobertoisc_result_t
116d54cfbdrobertoisc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
117d54cfbdroberto
118d54cfbdrobertoisc_result_t
119d54cfbdrobertoisc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
120d54cfbdroberto
121d54cfbdrobertoisc_result_t
122d54cfbdrobertoisc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
123d54cfbdroberto
124d54cfbdrobertoisc_result_t
125d54cfbdrobertoisc_rwlock_tryupgrade(isc_rwlock_t *rwl);
126d54cfbdroberto
127d54cfbdrobertovoid
128d54cfbdrobertoisc_rwlock_downgrade(isc_rwlock_t *rwl);
129d54cfbdroberto
130d54cfbdrobertovoid
131d54cfbdrobertoisc_rwlock_destroy(isc_rwlock_t *rwl);
132d54cfbdroberto
133d54cfbdrobertoISC_LANG_ENDDECLS
134d54cfbdroberto
135d54cfbdroberto#endif /* ISC_RWLOCK_H */
136