1135446Strhodes/*
2193149Sdougb * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id: rwlock.h,v 1.28 2007/06/19 23:47:18 tbox Exp $ */
19135446Strhodes
20135446Strhodes#ifndef ISC_RWLOCK_H
21135446Strhodes#define ISC_RWLOCK_H 1
22135446Strhodes
23193149Sdougb/*! \file isc/rwlock.h */
24170222Sdougb
25135446Strhodes#include <isc/condition.h>
26135446Strhodes#include <isc/lang.h>
27135446Strhodes#include <isc/platform.h>
28135446Strhodes#include <isc/types.h>
29135446Strhodes
30135446StrhodesISC_LANG_BEGINDECLS
31135446Strhodes
32135446Strhodestypedef enum {
33135446Strhodes	isc_rwlocktype_none = 0,
34135446Strhodes	isc_rwlocktype_read,
35135446Strhodes	isc_rwlocktype_write
36135446Strhodes} isc_rwlocktype_t;
37135446Strhodes
38135446Strhodes#ifdef ISC_PLATFORM_USETHREADS
39170222Sdougb#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
40170222Sdougb#define ISC_RWLOCK_USEATOMIC 1
41170222Sdougb#endif
42170222Sdougb
43135446Strhodesstruct isc_rwlock {
44135446Strhodes	/* Unlocked. */
45135446Strhodes	unsigned int		magic;
46135446Strhodes	isc_mutex_t		lock;
47170222Sdougb
48170222Sdougb#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
49170222Sdougb	/*
50170222Sdougb	 * When some atomic instructions with hardware assistance are
51170222Sdougb	 * available, rwlock will use those so that concurrent readers do not
52170222Sdougb	 * interfere with each other through mutex as long as no writers
53170222Sdougb	 * appear, massively reducing the lock overhead in the typical case.
54170222Sdougb	 *
55170222Sdougb	 * The basic algorithm of this approach is the "simple
56170222Sdougb	 * writer-preference lock" shown in the following URL:
57170222Sdougb	 * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html
58170222Sdougb	 * but our implementation does not rely on the spin lock unlike the
59170222Sdougb	 * original algorithm to be more portable as a user space application.
60170222Sdougb	 */
61170222Sdougb
62170222Sdougb	/* Read or modified atomically. */
63170222Sdougb	isc_int32_t		write_requests;
64170222Sdougb	isc_int32_t		write_completions;
65170222Sdougb	isc_int32_t		cnt_and_flag;
66170222Sdougb
67135446Strhodes	/* Locked by lock. */
68135446Strhodes	isc_condition_t		readable;
69135446Strhodes	isc_condition_t		writeable;
70170222Sdougb	unsigned int		readers_waiting;
71170222Sdougb
72170222Sdougb	/* Locked by rwlock itself. */
73170222Sdougb	unsigned int		write_granted;
74170222Sdougb
75170222Sdougb	/* Unlocked. */
76170222Sdougb	unsigned int		write_quota;
77170222Sdougb
78170222Sdougb#else  /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
79170222Sdougb
80170222Sdougb	/*%< Locked by lock. */
81170222Sdougb	isc_condition_t		readable;
82170222Sdougb	isc_condition_t		writeable;
83135446Strhodes	isc_rwlocktype_t	type;
84135446Strhodes
85170222Sdougb	/*% The number of threads that have the lock. */
86135446Strhodes	unsigned int		active;
87135446Strhodes
88170222Sdougb	/*%
89135446Strhodes	 * The number of lock grants made since the lock was last switched
90135446Strhodes	 * from reading to writing or vice versa; used in determining
91135446Strhodes	 * when the quota is reached and it is time to switch.
92135446Strhodes	 */
93135446Strhodes	unsigned int		granted;
94135446Strhodes
95135446Strhodes	unsigned int		readers_waiting;
96135446Strhodes	unsigned int		writers_waiting;
97135446Strhodes	unsigned int		read_quota;
98135446Strhodes	unsigned int		write_quota;
99135446Strhodes	isc_rwlocktype_t	original;
100170222Sdougb#endif  /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
101135446Strhodes};
102135446Strhodes#else /* ISC_PLATFORM_USETHREADS */
103135446Strhodesstruct isc_rwlock {
104135446Strhodes	unsigned int		magic;
105135446Strhodes	isc_rwlocktype_t	type;
106135446Strhodes	unsigned int		active;
107135446Strhodes};
108135446Strhodes#endif /* ISC_PLATFORM_USETHREADS */
109135446Strhodes
110135446Strhodes
111135446Strhodesisc_result_t
112135446Strhodesisc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
113135446Strhodes		unsigned int write_quota);
114135446Strhodes
115135446Strhodesisc_result_t
116135446Strhodesisc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
117135446Strhodes
118135446Strhodesisc_result_t
119135446Strhodesisc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
120135446Strhodes
121135446Strhodesisc_result_t
122135446Strhodesisc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
123135446Strhodes
124135446Strhodesisc_result_t
125135446Strhodesisc_rwlock_tryupgrade(isc_rwlock_t *rwl);
126135446Strhodes
127135446Strhodesvoid
128135446Strhodesisc_rwlock_downgrade(isc_rwlock_t *rwl);
129135446Strhodes
130135446Strhodesvoid
131135446Strhodesisc_rwlock_destroy(isc_rwlock_t *rwl);
132135446Strhodes
133135446StrhodesISC_LANG_ENDDECLS
134135446Strhodes
135135446Strhodes#endif /* ISC_RWLOCK_H */
136