* src/vm/jit/asmpart.h (calljava_xhandler2): Not required anymore.
[cacao.git] / src / threads / green / locks.c
1 /* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */
2 /*
3  * locks.c
4  * Manage locking system
5  * This include the mutex's and cv's.
6  *
7  * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK.
8  *
9  * See the file "license.terms" for information on usage and redistribution
10  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11  *
12  * Written by Tim Wilkinson <tim@tjwassoc.demon.co.uk>, 1996.
13  */
14
15
16 #include <assert.h>
17 #include <stdio.h>
18
19 #include "config.h"
20 #include "mm/memory.h"
21 #include "native/native.h"
22 #include "threads/green/threads.h"
23 #include "threads/green/locks.h"
24 #include "vm/builtin.h"
25 #include "vm/exceptions.h"
26 #include "vm/loader.h"
27 #include "vm/tables.h"
28
29
30 extern thread* currentThread;
31
32 mutexHashEntry *mutexHashTable;
33 int mutexHashTableSize;
34 long mutexHashMask;
35
36 mutexHashEntry *mutexOverflowTable;
37 int mutexOverflowTableSize;
38 mutexHashEntry *firstFreeOverflowEntry = 0;
39
40 conditionHashEntry *conditionHashTable;
41 int conditionHashTableSize;
42 long conditionHashMask;
43
44 /*
45  * Init the tables.
46  */
47 void
48 lock_init (void)
49 {
50     int i;
51
52     mutexHashTableSize = MUTEX_HASH_TABLE_SIZE;
53     mutexHashTable = MNEW(mutexHashEntry, mutexHashTableSize);
54     mutexHashMask = (mutexHashTableSize - 1) << 3;
55
56     for (i = 0; i < mutexHashTableSize; ++i)
57     {
58                 mutexHashTable[i].object = 0;
59                 mutexHashTable[i].mutex.holder = 0;
60                 mutexHashTable[i].mutex.count = 0;
61                 mutexHashTable[i].mutex.muxWaiters = 0;
62                 mutexHashTable[i].conditionCount = 0;
63                 mutexHashTable[i].next = 0;
64     }
65
66     mutexOverflowTableSize = MUTEX_OVERFLOW_TABLE_SIZE;
67     mutexOverflowTable = MNEW(mutexHashEntry, mutexOverflowTableSize);
68
69     firstFreeOverflowEntry = &mutexOverflowTable[0];
70
71     for (i = 0; i < mutexOverflowTableSize; ++i)
72     {
73                 mutexOverflowTable[i].object = 0;
74                 mutexOverflowTable[i].mutex.holder = 0;
75                 mutexOverflowTable[i].mutex.count = 0;
76                 mutexOverflowTable[i].mutex.muxWaiters = 0;
77                 mutexOverflowTable[i].conditionCount = 0;
78                 mutexOverflowTable[i].next = &mutexOverflowTable[i + 1];
79     }
80     mutexOverflowTable[i - 1].next = 0;
81
82     conditionHashTableSize = CONDITION_HASH_TABLE_SIZE;
83     conditionHashTable = MNEW(conditionHashEntry, conditionHashTableSize);
84     conditionHashMask = (conditionHashTableSize - 1) << 3;
85
86     for (i = 0; i < conditionHashTableSize; ++i)
87     {
88                 conditionHashTable[i].object = 0;
89                 conditionHashTable[i].condition.cvWaiters = 0;
90                 conditionHashTable[i].condition.mux = 0;
91     }
92 }
93
94
95 /*
96  * Reorders part of the condition hash table. Must be called after an entry has been deleted.
97  */
98 void
99 reorderConditionHashTable (int begin)
100 {
101     while (conditionHashTable[begin].object != 0)
102     {
103         int hashValue = CONDITION_HASH_VALUE(conditionHashTable[begin].object);
104
105         if (hashValue != begin)
106         {
107             while (conditionHashTable[hashValue].object != 0)
108             {
109                 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
110                 if (hashValue == begin)
111                     break;
112             }
113             if (hashValue != begin)
114             {
115                 conditionHashTable[hashValue] = conditionHashTable[begin];
116                 conditionHashTable[begin].object = 0;
117                 conditionHashTable[begin].condition.cvWaiters = 0;
118                 conditionHashTable[begin].condition.mux = 0;
119             }
120         }
121
122         begin = CONDITION_HASH_SUCCESSOR(begin);
123     }
124 }
125
126 /*
127  * Looks up an entry in the condition hash table.
128  */
129 iCv*
130 conditionForObject (java_objectheader *object)
131 {
132     int hashValue;
133
134     intsDisable();
135
136     hashValue = CONDITION_HASH_VALUE(object);
137     while (conditionHashTable[hashValue].object != object
138                    && conditionHashTable[hashValue].object != 0)
139                 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
140
141     if (conditionHashTable[hashValue].object == 0)
142     {
143                 intsRestore();
144                 return 0;
145     }
146     
147     intsRestore();
148     return &conditionHashTable[hashValue].condition;
149 }
150
151 /*
152  * Adds a new entry in the condition hash table and returns a pointer to the condition
153  */
154 iCv*
155 addConditionForObject (java_objectheader *object)
156 {
157     int hashValue;
158
159     intsDisable();
160
161     hashValue = CONDITION_HASH_VALUE(object);
162     while (conditionHashTable[hashValue].object != 0)
163                 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
164
165     conditionHashTable[hashValue].object = object;
166
167     intsRestore();
168
169     return &conditionHashTable[hashValue].condition;
170 }
171
172 /*
173  * Removes an entry from the condition hash table.
174  */
175 void
176 removeConditionForObject (java_objectheader *object)
177 {
178     int hashValue;
179
180     intsDisable();
181
182     hashValue = CONDITION_HASH_VALUE(object);
183     while (conditionHashTable[hashValue].object != object)
184                 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
185
186     conditionHashTable[hashValue].object = 0;
187     conditionHashTable[hashValue].condition.cvWaiters = 0;
188     conditionHashTable[hashValue].condition.mux = 0;
189
190     reorderConditionHashTable(CONDITION_HASH_SUCCESSOR(hashValue));
191
192     intsRestore();
193 }
194
195 /*
196  * Returns the mutex entry for the specified object and increments its conditionCount.
197  */
198 mutexHashEntry*
199 conditionLockedMutexForObject (java_objectheader *object)
200 {
201     int hashValue;
202     mutexHashEntry *entry;
203
204     assert(object != 0);
205
206     intsDisable();
207
208     hashValue = MUTEX_HASH_VALUE(object);
209     entry = &mutexHashTable[hashValue];
210
211     if (entry->object != 0)
212     {
213                 if (entry->mutex.count == 0 && entry->conditionCount == 0)
214                 {
215                         entry->object = 0;
216                         entry->mutex.holder = 0;
217                         entry->mutex.count = 0;
218                         entry->mutex.muxWaiters = 0;
219                 }
220                 else
221                 {
222                         while (entry->next != 0 && entry->object != object)
223                                 entry = entry->next;
224
225                         if (entry->object != object)
226                         {
227                                 entry->next = firstFreeOverflowEntry;
228                                 firstFreeOverflowEntry = firstFreeOverflowEntry->next;
229                                 
230                                 entry = entry->next;
231                                 entry->object = 0;
232                                 entry->next = 0;
233                                 assert(entry->conditionCount == 0);
234                         }
235                 }
236     }
237
238     if (entry->object == 0)
239         entry->object = object;
240
241     ++entry->conditionCount;
242
243     intsRestore();
244
245     return entry;
246 }
247
248 /*
249  * Wait for the condition of an object to be signalled
250  */
251 void
252 lock_wait_for_object (java_objectheader *obj, s8 time, s4 par3)
253 {
254     iCv *condition;
255     mutexHashEntry *mutexEntry;
256
257     intsDisable();
258
259     mutexEntry = conditionLockedMutexForObject(obj);
260
261     condition = conditionForObject(obj);
262     if (condition == 0)
263                 condition = addConditionForObject(obj);
264
265     DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
266
267     internal_wait_cond(&mutexEntry->mutex, condition, time);
268
269     if (condition->cvWaiters == 0 && condition->mux == 0)
270                 removeConditionForObject(obj);
271     --mutexEntry->conditionCount;
272
273     intsRestore();
274 }
275
276 /*
277  * Signal the condition of an object
278  */
279 void
280 lock_notify_object (java_objectheader *obj)
281 {
282     iCv *condition;
283
284     intsDisable();
285
286     condition = conditionForObject(obj);
287     if (condition == 0)
288                 condition = addConditionForObject(obj);
289
290     DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
291     
292     internal_signal_cond(condition);
293
294     if (condition->cvWaiters == 0 && condition->mux == 0)
295                 removeConditionForObject(obj);
296
297     intsRestore();
298 }
299
300 /*
301  * Broadcast the condition of an object.
302  */
303 void
304 lock_notify_all_object (java_objectheader *obj)
305 {
306         intsDisable();
307         internal_lock_notify_all_object(obj);
308         intsRestore();
309 }
310
311 /*
312  * Internal: Broadcast the condition of an object.
313  */
314 void
315 internal_lock_notify_all_object (java_objectheader *obj)
316 {
317     iCv *condition;
318
319     condition = conditionForObject(obj);
320     if (condition == 0)
321                 condition = addConditionForObject(obj);
322
323     internal_broadcast_cond(condition);
324
325     if (condition->cvWaiters == 0 && condition->mux == 0)
326                 removeConditionForObject(obj);
327 }
328
329 /*
330  * Lock a mutex.
331  */
332 void
333 lock_mutex (iMux *mux)
334 {
335         intsDisable();
336         internal_lock_mutex(mux);
337         intsRestore();
338 }
339
340 /*
341  * Lock the mutex for an object.
342  */
343 void
344 lock_mutex_for_object (java_objectheader *obj)
345 {
346         intsDisable();
347         internal_lock_mutex_for_object(obj);
348         intsRestore();
349 }
350
351 /*
352  * Unlock a mutex.
353  */
354 void
355 unlock_mutex (iMux *mux)
356 {
357         intsDisable();
358         internal_unlock_mutex(mux);
359         intsRestore();
360 }
361
362 /*
363  * Unlock the mutex for an object.
364  */
365 void
366 unlock_mutex_for_object (java_objectheader *obj)
367 {
368         intsDisable();
369         internal_unlock_mutex_for_object(obj);
370         intsRestore();
371 }
372
373 /*
374  * Wait on a condition variable.
375  */
376 void
377 wait_cond (iMux *mux, iCv *cond, s8 timeout)
378 {
379         intsDisable();
380         internal_wait_cond(mux, cond, timeout);
381         intsRestore();
382 }
383
384 /*
385  * Signal a condition variable.
386  */
387 void
388 signal_cond (iCv *cond)
389 {
390         intsDisable();
391         internal_signal_cond(cond);
392         intsRestore();
393 }
394
395 /*
396  * Broadcast a condition variable.
397  */
398 void
399 broadcast_cond (iCv *cond)
400 {
401         intsDisable();
402         internal_broadcast_cond(cond);
403         intsRestore();
404 }
405
406 /*
407  * Internal: Lock a mutex.
408  */
409 void
410 internal_lock_mutex(iMux* mux)
411 {
412         assert(blockInts > 0);
413
414     if (mux->holder == 0)
415     {
416                 mux->holder = currentThread;
417                 mux->count = 1;
418                 DBG( fprintf(stderr, "set holder of %p to %p\n", mux, mux->holder); )
419     }
420     else if (mux->holder == currentThread)
421     {
422                 mux->count++;
423     }
424     else
425     {
426                 while (mux->holder != 0)
427                 {
428                         suspendOnQThread(currentThread, &mux->muxWaiters);
429                 }
430                 mux->holder = currentThread;
431                 mux->count = 1;
432     }
433 }
434
435 /*
436  * Internal: Release a mutex.
437  */
438 void
439 internal_unlock_mutex(iMux* mux)
440 {
441     thread* tid;
442
443         assert(blockInts > 0);
444
445     assert(mux->holder == currentThread);
446     
447     mux->count--;
448     if (mux->count == 0)
449     {
450                 mux->holder = 0;
451                 if (mux->muxWaiters != 0)
452                 {
453                         tid = mux->muxWaiters;
454                         mux->muxWaiters = tid->vmThread->next;
455                         iresumeThread(tid);
456                 }
457     }
458 }
459
460 /*
461  * Internal: Wait on a conditional variable.
462  *  (timeout currently ignored)
463  */
464 void
465 internal_wait_cond(iMux* mux, iCv* cv, s8 timeout)
466 {
467     int count;
468     thread* tid;
469
470     DBG( fprintf(stderr, "waiting on %p\n", cv); );
471
472     if (mux->holder != currentThread) {
473                 *exceptionptr = new_exception(string_java_lang_IllegalMonitorStateException);
474     }
475
476         assert(blockInts > 0);
477
478     count = mux->count;
479     mux->holder = 0;
480     mux->count = 0;
481     cv->mux = mux;
482
483     /* If there's anyone waiting here, wake them up */
484     if (mux->muxWaiters != 0) {
485                 tid = mux->muxWaiters;
486                 mux->muxWaiters = tid->vmThread->next;
487                 iresumeThread(tid);
488     }
489
490     /* Suspend, and keep suspended until I re-get the lock */
491     suspendOnQThread(currentThread, &cv->cvWaiters);
492     while (mux->holder != 0) {
493                 DBG( fprintf(stderr, "woke up\n"); );
494                 suspendOnQThread(currentThread, &mux->muxWaiters);
495     }
496
497     mux->holder = currentThread;
498     mux->count = count;
499 }
500
501 /*
502  * Internal: Wake one thread on a conditional variable.
503  */
504 void
505 internal_signal_cond (iCv* cv)
506 {
507     thread* tid;
508
509     DBG( fprintf(stderr, "signalling on %p\n", cv); );
510
511     /* If 'mux' isn't set then we've never waited on this object. */
512     if (cv->mux == 0) {
513                 return;
514     }
515
516     if (cv->mux->holder != currentThread) {
517                 *exceptionptr = new_exception(string_java_lang_IllegalMonitorStateException);
518     }
519
520         assert(blockInts > 0);
521
522     /* Remove one thread from cv list */
523     if (cv->cvWaiters != 0) {
524                 DBG( fprintf(stderr, "releasing a waiter\n"); );
525
526                 tid = cv->cvWaiters;
527                 cv->cvWaiters = tid->vmThread->next;
528
529                 /* Place it on mux list */
530                 tid->vmThread->next = cv->mux->muxWaiters;
531                 cv->mux->muxWaiters = tid;
532     }
533 }
534
535 /*
536  * Internal: Wake all threads on a conditional variable.
537  */
538 void
539 internal_broadcast_cond (iCv* cv)
540 {
541     thread** tidp;
542
543     /* If 'mux' isn't set then we've never waited on this object. */
544     if (cv->mux == 0) {
545                 return;
546     }
547
548     if (cv->mux->holder != currentThread) {
549                 *exceptionptr = new_exception(string_java_lang_IllegalMonitorStateException);
550     }
551
552         assert(blockInts > 0);
553
554     /* Find the end of the cv list */
555     if (cv->cvWaiters) {
556                 for (tidp = &cv->cvWaiters; *tidp != 0; tidp = &(*tidp)->vmThread->next)
557                         ;
558
559                 /* Place entire cv list on mux list */
560                 (*tidp) = cv->mux->muxWaiters;
561                 cv->mux->muxWaiters = cv->cvWaiters;
562                 cv->cvWaiters = 0;
563     }
564 }
565
566
567 /*
568  * These are local overrides for various environment variables in Emacs.
569  * Please do not remove this and leave it at the end of the file, where
570  * Emacs will automagically detect them.
571  * ---------------------------------------------------------------------
572  * Local variables:
573  * mode: c
574  * indent-tabs-mode: t
575  * c-basic-offset: 4
576  * tab-width: 4
577  * End:
578  */