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