1 /*********************************************
2 * File: netsync.h
3 * Purpose: NETAPI Synchronization primitives
4 **************************************************************
5 * FILE: netsync.h
6 *
7 * DESCRIPTION: netapi synch utilities header file for user space transport
8 * library
9 *
10 * REVISION HISTORY: rev 0.0.1
11 *
12 * Copyright (c) Texas Instruments Incorporated 2010-2011
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 *
18 * Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 *
21 * Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the
24 * distribution.
25 *
26 * Neither the name of Texas Instruments Incorporated nor the names of
27 * its contributors may be used to endorse or promote products derived
28 * from this software without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 **********************************************/
43 #ifndef NETAPI_SYNC_H
44 #define NETAPI_SYNCH_H
46 /*--------------------------*/
47 /*----------spinlock--------*/
48 /*--------------------------*/
50 typedef int NETAPI_SPINLOCK_T;
52 #define NETAPI_SPINLOCK_LOCKVAL 1
53 #define NETAPI_SPINLOCK_UNLOCKVAL 0 //never change!!
54 #define NETAPI_SPINLOCK_UNLOCKED_INITIALIZER (NETAPI_SPINLOCK_UNLOCKVAL)
56 /* init a lock */
57 static inline void netapi_spinlock_init (NETAPI_SPINLOCK_T * val) {*val=NETAPI_SPINLOCK_UNLOCKVAL;}
59 /* lock a spinlock */
60 static inline void netapi_spinlock_lock(NETAPI_SPINLOCK_T * val)
61 {
62 while(__sync_lock_test_and_set(val, NETAPI_SPINLOCK_LOCKVAL))
63 {
64 asm volatile("nop" :: );
65 asm volatile("nop" :: );
66 asm volatile("nop" :: );
67 asm volatile("nop" :: );
68 }
69 }
71 /* try to get lock 1 time. Return 1 if ok, 0 if un-successful */
72 static inline int netapi_spinlock_try_lock( NETAPI_SPINLOCK_T* val)
73 {
74 int i=0;
75 if (__sync_lock_test_and_set(val, NETAPI_SPINLOCK_LOCKVAL)) return 0;
76 return 1;
77 }
80 /* unlock a spinlock. */
81 static inline void netapi_spinlock_unlock(NETAPI_SPINLOCK_T * val)
82 {
83 __sync_lock_release(val);
84 }
86 /* poll a lock, return 0 if unlocked, NETAPI_SPINLOCK_LOCKVAL if locked */
87 static inline int netapi_spinlock_is_locked(NETAPI_SPINLOCK_T * val)
88 {
89 return *val;
90 }
92 /*--------------------------*/
93 /*----------rwlock--------*/
94 /*--------------------------*/
96 /* a rw lock strucuture */
97 typedef struct RWLOCK_Tag
98 {
99 NETAPI_SPINLOCK_T lock_outer; //lock this structure. very short duration lock
100 NETAPI_SPINLOCK_T lock_w; //real write lock
101 unsigned long n_readers; /* # readers active */
102 } NETAPI_RWLOCK_T;
104 //initialize a rw lock
105 static inline void netapi_rwlock_init(NETAPI_RWLOCK_T * p_lock)
106 {
107 netapi_spinlock_init(&p_lock->lock_outer);
108 netapi_spinlock_init(&p_lock->lock_w);
109 p_lock->n_readers=0;
110 }
112 // lock a write lock.
113 static inline void netapi_rwlock_write_lock(NETAPI_RWLOCK_T * p_lock)
114 {
115 int ret;
116 while(1)
117 {
118 netapi_spinlock_lock(&p_lock->lock_outer); //get outer lock - now nothing can change
119 // check for 0 readers
120 if(p_lock->n_readers)
121 {
122 netapi_spinlock_unlock(&p_lock->lock_outer); //give up outer & spin
123 asm volatile("nop" :: );
124 asm volatile("nop" :: );
125 asm volatile("nop" :: );
126 asm volatile("nop" :: );
127 continue;
128 }
130 //ok, no readers. see if we can get writer lock
131 ret=netapi_spinlock_try_lock(&p_lock->lock_w); //try get writer lock 1 time
132 if(!ret)
133 {
134 netapi_spinlock_unlock(&p_lock->lock_outer); //give up outer & spin
135 asm volatile("nop" :: );
136 asm volatile("nop" :: );
137 asm volatile("nop" :: );
138 asm volatile("nop" :: );
139 continue; /* try again */
140 }
141 netapi_spinlock_unlock(&p_lock->lock_outer); //got write lock=> no other writer, no readers! Keep the writelock but unlock the outer.
142 return;
143 }
144 }
146 //unlock a writer part of rwlock */
147 static inline void netapi_rwlock_write_unlock(NETAPI_RWLOCK_T * p_lock)
148 {
149 netapi_spinlock_unlock(&p_lock->lock_w);
150 }
152 //grab a read lock
153 //=> can be other readers, but no writer
154 static inline void netapi_rwlock_read_lock(NETAPI_RWLOCK_T * p_lock)
155 {
156 int ret;
158 while(1)
159 {
160 /*1st grab outer lock. once we have it, nothing can change */
161 netapi_spinlock_lock(&p_lock->lock_outer);
163 /* see if there is a writer */
164 ret= netapi_spinlock_is_locked(&p_lock->lock_w);
166 //there is a writer
167 if (ret)
168 {
169 netapi_spinlock_unlock(&p_lock->lock_outer); //give up outer and spin
170 asm volatile("nop" :: );
171 asm volatile("nop" :: );
172 asm volatile("nop" :: );
173 asm volatile("nop" :: );
174 continue;
175 }
177 /* there is no writer so we can read!*/
178 p_lock->n_readers+=1;
180 /* mb ? */
181 __sync_synchronize(); //make sure every core sees that n_readers has changed
183 /* now give back the outer lock */
184 netapi_spinlock_unlock(&p_lock->lock_outer);
185 return;
186 }
187 }
189 //rw_lock reader unlock
190 static inline void netapi_rwlock_read_unlock(NETAPI_RWLOCK_T * p_lock)
191 {
192 //grab outer
193 netapi_spinlock_lock(&p_lock->lock_outer);
195 //decrement # of readers. Make sure all cores see update
196 p_lock->n_readers--;
197 __sync_synchronize();
198 //TBD: need to check for <0?
200 /* give up the outer */
201 netapi_spinlock_unlock(&p_lock->lock_outer);
202 }
204 /*--------------------------*/
205 /*----------atomic32--------*/
206 /*--------------------------*/
207 typedef struct NETAPI_ATOMIC32_tag
208 {
209 long val;
210 } NETAPI_ATOMIC32_T;
212 #define NETAPI_ATOMIC_INIT32(x) {x}
213 static inline int netapi_atomic_read32(NETAPI_ATOMIC32_T *p) {return p->val;}
215 static inline void netapi_atomic_set32(NETAPI_ATOMIC32_T *p, int val)
216 {__sync_fetch_and_add(&p->val,0); } //todo crude, why not p->val=val?
218 static inline void netapi_atomic_add32(NETAPI_ATOMIC32_T *p, int val)
219 {__sync_fetch_and_add(&p->val,val);}
221 static inline void netapi_atomic_sub32(NETAPI_ATOMIC32_T *p, int val)
222 {__sync_fetch_and_sub(&p->val,val);}
224 #define NETAPI_atomic_inc32(p) netapi_atomic_add32(p,1);
225 #define NETAPI_atomic_dec32(p) netapi_atomic_sub32(p,1);
227 static inline int netapi_atomic_add_return32(NETAPI_ATOMIC32_T *p, int val)
228 {return __sync_add_and_fetch(&p->val,val);}
230 static inline int netapi_atomic_sub_return32(NETAPI_ATOMIC32_T *p, int val)
231 {return __sync_sub_and_fetch(&p->val,val);}
233 static inline int netapi_atomic_inc_and_test32(NETAPI_ATOMIC32_T *p)
234 {return __sync_add_and_fetch(&p->val,1);}
236 static inline int netapi_atomic_dec_and_test32(NETAPI_ATOMIC32_T *p)
237 {return !__sync_sub_and_fetch(&p->val,1);}
239 static inline int netapi_atomic_test_and_set32(NETAPI_ATOMIC32_T *p)
240 {return (! _sync_lock_test_and_set(p, 1));}
242 #define netapi_atomic_clear32(p) netapi_atomic_set32(p,0);
244 /*--------------------------*/
245 /*----------atomic64--------*/
246 /*--------------------------*/
247 typedef struct NETAPI_ATOMIC64_Tag
248 {
249 NETAPI_SPINLOCK_T lock;
250 long long val;
251 } NETAPI_ATOMIC64_T;
253 #define NETAPI_ATOMIC_INIT64(x) {NETAPI_SPINLOCK_UNLOCKED_INITIALIZER,x}
255 static inline long long netapi_atomic_read64(NETAPI_ATOMIC64_T *p)
256 {
257 long long latch_val;
258 netapi_spinlock_lock(&p->lock); //acquire lock
259 latch_val = p->val;
260 netapi_spinlock_unlock(&p->lock); //free lock
261 return latch_val;
262 }
264 static inline void netapi_atomic_set64(NETAPI_ATOMIC64_T *p,long long val)
265 {
266 netapi_spinlock_lock(&p->lock); //acquire lock
267 p->val = val;
268 //__sync_synchronize(); //todo: may not need as unlock will do this also probably
269 netapi_spinlock_unlock(&p->lock); //free lock
270 }
272 static inline void netapi_atomic_add64(NETAPI_ATOMIC64_T *p, long long val)
273 {
274 netapi_spinlock_lock(&p->lock); //acquire lock
275 p->val += val;
276 //__sync_synchronize(); //todo: may not need as unlock will do this also probably
277 netapi_spinlock_unlock(&p->lock); //free lock
278 }
280 /*******************************************************
281 ****************memory barrier************************
282 ******************************************************/
283 static inline void netapi_mb(){__sync_synchronize();}
284 static inline void netapi_rmb(){__sync_synchronize();}
285 static inline void netapi_wmb(){__sync_synchronize();}
288 #endif