1 /* $Id: token.h,v 1.3 2010/06/05 19:37:27 fredette Exp $ */
2 
3 /* tme/token.h - header file for token functions: */
4 
5 /*
6  * Copyright (c) 2008 Matt Fredette
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Matt Fredette.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #ifndef _TME_TOKEN_H
37 #define _TME_TOKEN_H
38 
39 #include <tme/common.h>
40 _TME_RCSID("$Id: token.h,v 1.3 2010/06/05 19:37:27 fredette Exp $");
41 
42 /* includes: */
43 #include <tme/threads.h>
44 #include <tme/memory.h>
45 
46 /* macros: */
47 
48 /* this returns nonzero if a token is valid: */
49 #define tme_token_is_valid(token)					\
50   (__tme_predict_true(!tme_memory_atomic_read_flag(&(token)->tme_token_invalid)))
51 
52 /* this returns nonzero if a token is invalid: */
53 #define tme_token_is_invalid(token)					\
54   (__tme_predict_false(tme_memory_atomic_read_flag(&(token)->tme_token_invalid)))
55 
56 /* this internal macro busies or unbusies a token: */
57 #ifndef TME_NO_DEBUG_LOCKS
58 #define _tme_token_busy_change(token, x)				\
59   do {									\
60     assert ((!tme_memory_atomic_read_flag(&(token)->tme_token_busy))\
61 	    != !(x));							\
62     tme_memory_atomic_write_flag(&(token)->tme_token_busy, x);		\
63     (token)->_tme_token_busy_file = __FILE__;				\
64     (token)->_tme_token_busy_line = __LINE__;				\
65   } while (/* CONSTCOND */ 0)
66 #elif !TME_THREADS_COOPERATIVE
67 #define _tme_token_busy_change(token, x)				\
68   tme_memory_atomic_write_flag(&(token)->tme_token_busy, x)
69 #else  /* TME_THREADS_COOPERATIVE && defined(TME_NO_DEBUG_LOCKS) */
70 #define _tme_token_busy_change(token, x)				\
71   do { } while (0 && tme_memory_atomic_read_flag(&(token)->tme_token_invalid) && (x))
72 #endif /* TME_THREADS_COOPERATIVE && defined(TME_NO_DEBUG_LOCKS) */
73 
74 /* this busies a token: */
75 /* NB: a token must be busied before its validity can be checked.
76    tme_token_busy() automatically makes a write-before-read barrier on
77    the token to order itself with a subsequent tme_token_is_valid() or
78    tme_token_is_invalid(), and the caller generally won't need to make
79    any additional barrier to order reads after a validity check
80    (because tokens can only be asynchronously invalidated, not
81    validated).  however, a caller may need to make write-before-write
82    barriers to order any writes before a tme_token_unbusy(): */
83 #define tme_token_busy(token)						\
84   do {									\
85     _tme_token_busy_change(token, TRUE);				\
86     tme_memory_barrier(token,						\
87 		       sizeof(*token),					\
88 		       TME_MEMORY_BARRIER_WRITE_BEFORE_READ);		\
89   } while (/* CONSTCOND */ 0)
90 
91 /* this unbusies a token: */
92 #define tme_token_unbusy(token)		_tme_token_busy_change(token, FALSE)
93 
94 /* this invalidates a token without synchronizing: */
95 #define tme_token_invalidate_nosync(token)				\
96   tme_memory_atomic_write_flag(&(token)->tme_token_invalid, TRUE)
97 
98 /* types: */
99 
100 /* a token: */
101 struct tme_token {
102 
103   /* if this is nonzero, the token has been invalidated: */
104   tme_memory_atomic_flag_t tme_token_invalid;
105 
106 #if !TME_THREADS_COOPERATIVE || !defined(TME_NO_DEBUG_LOCKS)
107 
108   /* if this is nonzero, the token is busy: */
109   tme_memory_atomic_flag_t tme_token_busy;
110 
111   /* this mutex synchronizes tme_token_invalidate() and
112      tme_token_invalid_clear(): */
113   tme_mutex_t tme_token_invalid_mutex;
114 
115 #ifndef TME_NO_DEBUG_LOCKS
116 
117   /* the file and line number of the last busier or unbusier: */
118   _tme_const char *_tme_token_busy_file;
119   unsigned long _tme_token_busy_line;
120 
121 #endif /* !TME_NO_DEBUG_LOCKS */
122 
123 #endif /* !TME_THREADS_COOPERATIVE || !defined(TME_NO_DEBUG_LOCKS) */
124 };
125 
126 /* prototypes: */
127 void tme_token_init _TME_P((struct tme_token *));
128 void tme_token_invalidate _TME_P((struct tme_token *));
129 void tme_token_invalid_clear _TME_P((struct tme_token *));
130 
131 /* this wrapper macro predicts that the token doesn't need to be
132    cleared: */
133 #define tme_token_invalid_clear(token)		\
134   do {						\
135     if (tme_token_is_invalid(token)) {		\
136       tme_token_invalid_clear(token);		\
137     }						\
138   } while (/* CONSTCOND */ 0)
139 
140 #endif /* !_TME_TOKEN_H */
141