1 /* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */
4 * Manage locking system
5 * This include the mutex's and cv's.
7 * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK.
9 * See the file "license.terms" for information on usage and redistribution
10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 * Written by Tim Wilkinson <tim@tjwassoc.demon.co.uk>, 1996.
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"
30 extern thread* currentThread;
32 mutexHashEntry *mutexHashTable;
33 int mutexHashTableSize;
36 mutexHashEntry *mutexOverflowTable;
37 int mutexOverflowTableSize;
38 mutexHashEntry *firstFreeOverflowEntry = 0;
40 conditionHashEntry *conditionHashTable;
41 int conditionHashTableSize;
42 long conditionHashMask;
52 mutexHashTableSize = MUTEX_HASH_TABLE_SIZE;
53 mutexHashTable = MNEW(mutexHashEntry, mutexHashTableSize);
54 mutexHashMask = (mutexHashTableSize - 1) << 3;
56 for (i = 0; i < mutexHashTableSize; ++i)
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;
66 mutexOverflowTableSize = MUTEX_OVERFLOW_TABLE_SIZE;
67 mutexOverflowTable = MNEW(mutexHashEntry, mutexOverflowTableSize);
69 firstFreeOverflowEntry = &mutexOverflowTable[0];
71 for (i = 0; i < mutexOverflowTableSize; ++i)
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];
80 mutexOverflowTable[i - 1].next = 0;
82 conditionHashTableSize = CONDITION_HASH_TABLE_SIZE;
83 conditionHashTable = MNEW(conditionHashEntry, conditionHashTableSize);
84 conditionHashMask = (conditionHashTableSize - 1) << 3;
86 for (i = 0; i < conditionHashTableSize; ++i)
88 conditionHashTable[i].object = 0;
89 conditionHashTable[i].condition.cvWaiters = 0;
90 conditionHashTable[i].condition.mux = 0;
96 * Reorders part of the condition hash table. Must be called after an entry has been deleted.
99 reorderConditionHashTable (int begin)
101 while (conditionHashTable[begin].object != 0)
103 int hashValue = CONDITION_HASH_VALUE(conditionHashTable[begin].object);
105 if (hashValue != begin)
107 while (conditionHashTable[hashValue].object != 0)
109 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
110 if (hashValue == begin)
113 if (hashValue != begin)
115 conditionHashTable[hashValue] = conditionHashTable[begin];
116 conditionHashTable[begin].object = 0;
117 conditionHashTable[begin].condition.cvWaiters = 0;
118 conditionHashTable[begin].condition.mux = 0;
122 begin = CONDITION_HASH_SUCCESSOR(begin);
127 * Looks up an entry in the condition hash table.
130 conditionForObject (java_objectheader *object)
136 hashValue = CONDITION_HASH_VALUE(object);
137 while (conditionHashTable[hashValue].object != object
138 && conditionHashTable[hashValue].object != 0)
139 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
141 if (conditionHashTable[hashValue].object == 0)
148 return &conditionHashTable[hashValue].condition;
152 * Adds a new entry in the condition hash table and returns a pointer to the condition
155 addConditionForObject (java_objectheader *object)
161 hashValue = CONDITION_HASH_VALUE(object);
162 while (conditionHashTable[hashValue].object != 0)
163 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
165 conditionHashTable[hashValue].object = object;
169 return &conditionHashTable[hashValue].condition;
173 * Removes an entry from the condition hash table.
176 removeConditionForObject (java_objectheader *object)
182 hashValue = CONDITION_HASH_VALUE(object);
183 while (conditionHashTable[hashValue].object != object)
184 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
186 conditionHashTable[hashValue].object = 0;
187 conditionHashTable[hashValue].condition.cvWaiters = 0;
188 conditionHashTable[hashValue].condition.mux = 0;
190 reorderConditionHashTable(CONDITION_HASH_SUCCESSOR(hashValue));
196 * Returns the mutex entry for the specified object and increments its conditionCount.
199 conditionLockedMutexForObject (java_objectheader *object)
202 mutexHashEntry *entry;
208 hashValue = MUTEX_HASH_VALUE(object);
209 entry = &mutexHashTable[hashValue];
211 if (entry->object != 0)
213 if (entry->mutex.count == 0 && entry->conditionCount == 0)
216 entry->mutex.holder = 0;
217 entry->mutex.count = 0;
218 entry->mutex.muxWaiters = 0;
222 while (entry->next != 0 && entry->object != object)
225 if (entry->object != object)
227 entry->next = firstFreeOverflowEntry;
228 firstFreeOverflowEntry = firstFreeOverflowEntry->next;
233 assert(entry->conditionCount == 0);
238 if (entry->object == 0)
239 entry->object = object;
241 ++entry->conditionCount;
249 * Wait for the condition of an object to be signalled
252 lock_wait_for_object (java_objectheader *obj, s8 time, s4 par3)
255 mutexHashEntry *mutexEntry;
259 mutexEntry = conditionLockedMutexForObject(obj);
261 condition = conditionForObject(obj);
263 condition = addConditionForObject(obj);
265 DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
267 internal_wait_cond(&mutexEntry->mutex, condition, time);
269 if (condition->cvWaiters == 0 && condition->mux == 0)
270 removeConditionForObject(obj);
271 --mutexEntry->conditionCount;
277 * Signal the condition of an object
280 lock_notify_object (java_objectheader *obj)
286 condition = conditionForObject(obj);
288 condition = addConditionForObject(obj);
290 DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
292 internal_signal_cond(condition);
294 if (condition->cvWaiters == 0 && condition->mux == 0)
295 removeConditionForObject(obj);
301 * Broadcast the condition of an object.
304 lock_notify_all_object (java_objectheader *obj)
307 internal_lock_notify_all_object(obj);
312 * Internal: Broadcast the condition of an object.
315 internal_lock_notify_all_object (java_objectheader *obj)
319 condition = conditionForObject(obj);
321 condition = addConditionForObject(obj);
323 internal_broadcast_cond(condition);
325 if (condition->cvWaiters == 0 && condition->mux == 0)
326 removeConditionForObject(obj);
333 lock_mutex (iMux *mux)
336 internal_lock_mutex(mux);
341 * Lock the mutex for an object.
344 lock_mutex_for_object (java_objectheader *obj)
347 internal_lock_mutex_for_object(obj);
355 unlock_mutex (iMux *mux)
358 internal_unlock_mutex(mux);
363 * Unlock the mutex for an object.
366 unlock_mutex_for_object (java_objectheader *obj)
369 internal_unlock_mutex_for_object(obj);
374 * Wait on a condition variable.
377 wait_cond (iMux *mux, iCv *cond, s8 timeout)
380 internal_wait_cond(mux, cond, timeout);
385 * Signal a condition variable.
388 signal_cond (iCv *cond)
391 internal_signal_cond(cond);
396 * Broadcast a condition variable.
399 broadcast_cond (iCv *cond)
402 internal_broadcast_cond(cond);
407 * Internal: Lock a mutex.
410 internal_lock_mutex(iMux* mux)
412 assert(blockInts > 0);
414 if (mux->holder == 0)
416 mux->holder = currentThread;
418 DBG( fprintf(stderr, "set holder of %p to %p\n", mux, mux->holder); )
420 else if (mux->holder == currentThread)
426 while (mux->holder != 0)
428 suspendOnQThread(currentThread, &mux->muxWaiters);
430 mux->holder = currentThread;
436 * Internal: Release a mutex.
439 internal_unlock_mutex(iMux* mux)
443 assert(blockInts > 0);
445 assert(mux->holder == currentThread);
451 if (mux->muxWaiters != 0)
453 tid = mux->muxWaiters;
454 mux->muxWaiters = tid->vmThread->next;
461 * Internal: Wait on a conditional variable.
462 * (timeout currently ignored)
465 internal_wait_cond(iMux* mux, iCv* cv, s8 timeout)
470 DBG( fprintf(stderr, "waiting on %p\n", cv); );
472 if (mux->holder != currentThread) {
473 *exceptionptr = new_exception(string_java_lang_IllegalMonitorStateException);
476 assert(blockInts > 0);
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;
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);
497 mux->holder = currentThread;
502 * Internal: Wake one thread on a conditional variable.
505 internal_signal_cond (iCv* cv)
509 DBG( fprintf(stderr, "signalling on %p\n", cv); );
511 /* If 'mux' isn't set then we've never waited on this object. */
516 if (cv->mux->holder != currentThread) {
517 *exceptionptr = new_exception(string_java_lang_IllegalMonitorStateException);
520 assert(blockInts > 0);
522 /* Remove one thread from cv list */
523 if (cv->cvWaiters != 0) {
524 DBG( fprintf(stderr, "releasing a waiter\n"); );
527 cv->cvWaiters = tid->vmThread->next;
529 /* Place it on mux list */
530 tid->vmThread->next = cv->mux->muxWaiters;
531 cv->mux->muxWaiters = tid;
536 * Internal: Wake all threads on a conditional variable.
539 internal_broadcast_cond (iCv* cv)
543 /* If 'mux' isn't set then we've never waited on this object. */
548 if (cv->mux->holder != currentThread) {
549 *exceptionptr = new_exception(string_java_lang_IllegalMonitorStateException);
552 assert(blockInts > 0);
554 /* Find the end of the cv list */
556 for (tidp = &cv->cvWaiters; *tidp != 0; tidp = &(*tidp)->vmThread->next)
559 /* Place entire cv list on mux list */
560 (*tidp) = cv->mux->muxWaiters;
561 cv->mux->muxWaiters = cv->cvWaiters;
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 * ---------------------------------------------------------------------
574 * indent-tabs-mode: t