Merge branch 'hotfix-0.3.5'
[archipelago] / xseg / xtypes / xlock.h
1 /*
2  * Copyright 2012 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *   2. Redistributions in binary form must reproduce the above
12  *      copyright notice, this list of conditions and the following
13  *      disclaimer in the documentation and/or other materials
14  *      provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * The views and conclusions contained in the software and
30  * documentation are those of the authors and should not be
31  * interpreted as representing official policies, either expressed
32  * or implied, of GRNET S.A.
33  */
34
35 #ifndef _XLOCK_H
36 #define _XLOCK_H
37
38 #include <sys/util.h>
39
40 #define MFENCE() __sync_synchronize()
41 #define BARRIER() __asm__ __volatile__ ("" ::: "memory")
42 #define __pause() __asm__ __volatile__ ("pause\n");
43 #undef __pause
44 #define __pause()
45
46 #define Noone ((unsigned long)-1)
47
48 #define XLOCK_SANITY_CHECKS
49 #define XLOCK_CONGESTION_NOTIFY
50
51 #ifdef XLOCK_SANITY_CHECKS
52 #define MAX_VALID_OWNER 65536 /* we are not gonna have more ports than that */
53 #endif /* XLOCK_SANITY_CHECKS */
54
55 #ifdef XLOCK_CONGESTION_NOTIFY
56 #define MIN_SHIFT 20
57 #define MAX_SHIFT ((sizeof(unsigned long) * 8) -1)
58 #endif /* XLOCK_CONGESTION_NOTIFY */
59
60 struct xlock {
61         unsigned long owner;
62 };
63 //} __attribute__ ((aligned (16))); /* support up to 128bit longs */
64
65 static inline unsigned long xlock_acquire(struct xlock *lock, unsigned long who)
66 {
67         unsigned long owner;
68 #ifdef XLOCK_CONGESTION_NOTIFY
69         unsigned long times = 1;
70         unsigned long shift = MIN_SHIFT;
71 #endif /* XLOCK_CONGESTION_NOTIFY */
72
73         for (;;) {
74                 for (; (owner = *(volatile unsigned long *)(&lock->owner) != Noone);){
75 #ifdef XLOCK_SANITY_CHECKS
76                         if (owner > MAX_VALID_OWNER){
77                                 XSEGLOG("xlock %lx corrupted. Lock owner %lu",
78                                                 (unsigned long) lock, owner);
79                                 XSEGLOG("Resetting xlock %lx to Noone", 
80                                                 (unsigned long) lock);
81                                 lock->owner = Noone;
82                         }
83 #endif /* XLOCK_SANITY_CHECKS */
84 #ifdef XLOCK_CONGESTION_NOTIFY
85                         if (!(times & ((1<<shift) -1))){
86                                 XSEGLOG("xlock %lx spinned for %llu times"
87                                         "\n\t who: %lu, owner: %lu",
88                                         (unsigned long) lock, times,
89                                         who, owner);
90                                 if (shift < MAX_SHIFT)
91                                         shift++;
92 //                              xseg_printtrace();
93                         }
94                         times++;
95 #endif /* XLOCK_CONGESTION_NOTIFY */
96                         __pause();
97                 }
98
99                 if (__sync_bool_compare_and_swap(&lock->owner, Noone, who))
100                         break;
101         }
102 #ifdef XLOCK_SANITY_CHECKS
103         if (lock->owner > MAX_VALID_OWNER){
104                 XSEGLOG("xlock %lx locked with INVALID lock owner %lu",
105                                 (unsigned long) lock, lock->owner);
106         }
107 #endif /* XLOCK_SANITY_CHECKS */
108
109         return who;
110 }
111
112 static inline unsigned long xlock_try_lock(struct xlock *lock, unsigned long who)
113 {
114         return __sync_bool_compare_and_swap(&lock->owner, Noone, who);
115 }
116
117 static inline void xlock_release(struct xlock *lock)
118 {
119         BARRIER();
120         /*
121 #ifdef XLOCK_SANITY_CHECKS
122         if (lock->owner > MAX_VALID_OWNER){
123                 XSEGLOG("xlock %lx releasing lock with INVALID lock owner %lu",
124                                 (unsigned long) lock, lock->owner);
125         }
126 #endif 
127         */
128         /* XLOCK_SANITY_CHECKS */
129         lock->owner = Noone;
130 }
131
132 static inline unsigned long xlock_get_owner(struct xlock *lock)
133 {
134         return *(volatile unsigned long *)(&lock->owner);
135 }
136
137 #endif