Browse code

- lock optimizations: use the lock specific membar only if the lock_get operation succeeded (this means don't use it while spinning) => move the membar call in get_lock or try_lock

- added try_lock: like get_lock but doesn't block (returns -1 on failure
and 0 on success)

Andrei Pelinescu-Onciul authored on 03/04/2006 14:30:51
Showing 2 changed files
... ...
@@ -44,6 +44,10 @@
44 44
  *               unlock part (andrei)
45 45
  *  2006-03-08  mips2 NOSMP (skip sync), optimized x86 & mips clobbers and
46 46
  *               input/output constraints (andrei)
47
+ *  2006-04-03  optimization: call lock_get memory barrier outside tsl,in the 
48
+ *               calling function, only if the lock operation succeeded
49
+ *               (membar_getlock()) (andrei)
50
+ *              added try_lock()  (andrei)
47 51
  *
48 52
  */
49 53
 
... ...
@@ -67,8 +71,58 @@ typedef  volatile int fl_lock_t;
67 67
 #define init_lock( l ) (l)=0
68 68
 
69 69
 
70
+/* what membar to use (if any) after taking a lock. This
71
+ *  was separated from the lock code to allow better optimizations.
72
+ *  e.g.: use the membar_getlock only after getting the lock and don't use 
73
+ *  it if lock_get fails / when spinning on tsl.
74
+ *  There is no corresponding membar_release_lock (because lock_release
75
+ *  must always include the needed memory barrier).
76
+ *  WARNING: this is intended only for internal fastlock use*/
77
+#if defined(__CPU_i386) || defined(__CPU_x86_64)
78
+#define membar_getlock()   /* not needed on x86 */
79
+#elif defined(__CPU_sparc64) || defined(__CPU_sparc)
80
+#ifndef NOSMP
81
+#define membar_getlock() \
82
+	asm volatile ("membar #StoreStore | #StoreLoad \n\t" : : : "memory");
83
+#else
84
+/* no need for a compiler barrier, that is already included in lock_get/tsl*/
85
+#define membar_getlock() /* not needed if no smp*/
86
+#endif /* NOSMP */
87
+#elif defined __CPU_arm || defined __CPU_arm6
88
+#error "FIXME: check arm6 membar"
89
+#define membar_getlock() 
90
+#elif defined(__CPU_ppc) || defined(__CPU_ppc64)
91
+#ifndef NOSMP
92
+#define membar_getlock() \
93
+	asm volatile("lwsync \n\t" : : : "memory");
94
+#else
95
+#define membar_getlock() 
96
+#endif /* NOSMP */
97
+#elif defined __CPU_mips2 || ( defined __CPU_mips && defined MIPS_HAS_LLSC ) \
98
+	|| defined __CPU_mips64
99
+#ifndef NOSMP
100
+#define membar_getlock() \
101
+	asm volatile("sync \n\t" : : : "memory");
102
+#else
103
+#define membar_getlock() 
104
+#endif /* NOSMP */
105
+#elif defined __CPU_alpha
106
+#ifndef NOSMP
107
+#define membar_getlock() \
108
+	asm volatile("mb \n\t" : : : "memory");
109
+#else
110
+#define membar_getlock() 
111
+#endif /* NOSMP */
112
+#else
113
+#error "unknown architecture"
114
+#endif
115
+
116
+
70 117
 
71
-/*test and set lock, ret 1 if lock held by someone else, 0 otherwise*/
118
+/*test and set lock, ret 1 if lock held by someone else, 0 otherwise
119
+ * WARNING: no memory barriers included, if you use this function directly
120
+ *          (not recommended) and it gets the lock (ret==0), you should call 
121
+ *          membar_getlock() after it */
72 122
 inline static int tsl(fl_lock_t* lock)
73 123
 {
74 124
 	int val;
... ...
@@ -91,9 +145,7 @@ inline static int tsl(fl_lock_t* lock)
91 91
 #elif defined(__CPU_sparc64) || defined(__CPU_sparc)
92 92
 	asm volatile(
93 93
 			"ldstub [%1], %0 \n\t"
94
-#ifndef NOSMP
95
-			"membar #StoreStore | #StoreLoad \n\t"
96
-#endif
94
+			/* membar_getlock must be  called outside this function */
97 95
 			: "=r"(val) : "r"(lock):"memory"
98 96
 	);
99 97
 	
... ...
@@ -112,10 +164,7 @@ inline static int tsl(fl_lock_t* lock)
112 112
 			"   bne    0f\n\t"
113 113
 			"   stwcx. %1, 0, %2\n\t"
114 114
 			"   bne-   1b\n\t"
115
-			"   lwsync\n\t" /* lwsync or isync, lwsync is faster
116
-							   and should work, see
117
-							   [ IBM Programming environments Manual, D.4.1.1]
118
-							 */
115
+			/* membar_getlock must be  called outside this function */
119 116
 			"0:\n\t"
120 117
 			: "=r" (val)
121 118
 			: "r"(1), "b" (lock) :
... ...
@@ -134,9 +183,7 @@ inline static int tsl(fl_lock_t* lock)
134 134
 		"    sc %0, %2  \n\t"
135 135
 		"    beqz %0, 1b \n\t"
136 136
 		"    nop \n\t"
137
-#ifndef NOSMP
138
-		"    sync \n\t"
139
-#endif
137
+		/* membar_getlock must be called outside this function */
140 138
 		".set pop\n\t"
141 139
 		: "=&r" (tmp), "=&r" (val), "=m" (*lock) 
142 140
 		: "m" (*lock) 
... ...
@@ -154,7 +201,7 @@ inline static int tsl(fl_lock_t* lock)
154 154
 		"    lda %2, 1    \n\t"  /* or: or $31, 1, %2 ??? */
155 155
 		"    stl_c %2, %1 \n\t"
156 156
 		"    beq %2, 1b   \n\t"
157
-		"    mb           \n\t"
157
+		/* membar_getlock must be called outside this function */
158 158
 		"2:               \n\t"
159 159
 		:"=&r" (val), "=m"(*lock), "=r"(tmp)
160 160
 		:"m"(*lock) 
... ...
@@ -183,6 +230,20 @@ inline static void get_lock(fl_lock_t* lock)
183 183
 		sched_yield();
184 184
 #endif
185 185
 	}
186
+	membar_getlock();
187
+}
188
+
189
+
190
+
191
+/* like get_lock, but it doesn't wait. If it gets the lock returns 0,
192
+ *  <0  otherwise (-1) */
193
+inline static int try_lock(fl_lock_t* lock)
194
+{
195
+	if (tsl(lock)){
196
+		return -1;
197
+	}
198
+	membar_getlock();
199
+	return 0;
186 200
 }
187 201
 
188 202
 
... ...
@@ -1,4 +1,5 @@
1 1
 /*
2
+ * $Id$
2 3
  *
3 4
  *  simple locking test program
4 5
  *  (no paralles stuff)
... ...
@@ -23,18 +24,21 @@ int main(int argc, char** argv)
23 23
 	lock=0;
24 24
 	printf("starting locking basic tests...\n");
25 25
 	
26
-	r=tsl(&lock);
27
-	printf(" tsl should return 0                 ... %d\n", r);
26
+	r=try_lock(&lock);
27
+	printf(" try_lock should return 0            ... %d\n", r);
28 28
 	printf("     lock should be 1 now            ... %d\n", lock);
29
-	r=tsl(&lock);
30
-	printf(" tsl should return 1                 ... %d\n", r);
29
+	r=try_lock(&lock);
30
+	printf(" tsl should return -1                ... %d\n", r);
31 31
 	printf("     lock should still be 1 now      ... %d\n", lock);
32 32
 	release_lock(&lock);
33 33
 	printf(" release_lock: lock should be 0 now  ... %d\n", lock);
34
-	printf("trying tsl once more...\n");
35
-	r=tsl(&lock);
36
-	printf(" tsl should return 0                 ... %d\n", r);
34
+	printf("try_lock once more...\n");
35
+	r=try_lock(&lock);
36
+	printf(" try_lock should return 0            ... %d\n", r);
37 37
 	printf("     lock should be 1 now            ... %d\n", lock);
38
+	release_lock(&lock);
39
+	get_lock(&lock);
40
+	printf(" get_lock, lock should be 1 now      ... %d\n", lock);
38 41
 	printf("\ndone.\n");
39 42
 	return 0;
40 43
 }