This is the initial commit.
[keystone-rtos/netapi.git] / ti / runtime / netapi / netsync.h
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)
107         netapi_spinlock_init(&p_lock->lock_outer);
108         netapi_spinlock_init(&p_lock->lock_w);
109         p_lock->n_readers=0;
112 // lock a write lock.  
113 static inline void netapi_rwlock_write_lock(NETAPI_RWLOCK_T * p_lock)
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   }
146 //unlock a writer part of rwlock */
147 static inline void netapi_rwlock_write_unlock(NETAPI_RWLOCK_T * p_lock)
149   netapi_spinlock_unlock(&p_lock->lock_w);
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)
156 int ret;
158 while(1)
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;
189 //rw_lock reader unlock
190 static inline void netapi_rwlock_read_unlock(NETAPI_RWLOCK_T * p_lock)
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? 
199   
200   /* give up the outer */
201   netapi_spinlock_unlock(&p_lock->lock_outer);
204 /*--------------------------*/
205 /*----------atomic32--------*/
206 /*--------------------------*/
207 typedef struct NETAPI_ATOMIC32_tag
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
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)
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;
264 static inline void netapi_atomic_set64(NETAPI_ATOMIC64_T *p,long long val)
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
272 static inline void netapi_atomic_add64(NETAPI_ATOMIC64_T *p, long long val) 
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
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