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.
28 static classinfo *class_java_lang_IllegalMonitorStateException;
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 = (mutexHashEntry*)malloc(sizeof(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 = (mutexHashEntry*)malloc(sizeof(mutexHashEntry)
68 * mutexOverflowTableSize);
70 firstFreeOverflowEntry = &mutexOverflowTable[0];
72 for (i = 0; i < mutexOverflowTableSize; ++i)
74 mutexOverflowTable[i].object = 0;
75 mutexOverflowTable[i].mutex.holder = 0;
76 mutexOverflowTable[i].mutex.count = 0;
77 mutexOverflowTable[i].mutex.muxWaiters = 0;
78 mutexOverflowTable[i].conditionCount = 0;
79 mutexOverflowTable[i].next = &mutexOverflowTable[i + 1];
81 mutexOverflowTable[i - 1].next = 0;
83 conditionHashTableSize = CONDITION_HASH_TABLE_SIZE;
84 conditionHashTable = (conditionHashEntry*)malloc(sizeof(conditionHashEntry)
85 * conditionHashTableSize);
86 conditionHashMask = (conditionHashTableSize - 1) << 3;
88 for (i = 0; i < conditionHashTableSize; ++i)
90 conditionHashTable[i].object = 0;
91 conditionHashTable[i].condition.cvWaiters = 0;
92 conditionHashTable[i].condition.mux = 0;
95 /* Load exception classes */
96 loader_load_sysclass(&class_java_lang_IllegalMonitorStateException,
97 utf_new_char("java/lang/IllegalMonitorStateException"));
101 * Reorders part of the condition hash table. Must be called after an entry has been deleted.
104 reorderConditionHashTable (int begin)
106 while (conditionHashTable[begin].object != 0)
108 int hashValue = CONDITION_HASH_VALUE(conditionHashTable[begin].object);
110 if (hashValue != begin)
112 while (conditionHashTable[hashValue].object != 0)
114 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
115 if (hashValue == begin)
118 if (hashValue != begin)
120 conditionHashTable[hashValue] = conditionHashTable[begin];
121 conditionHashTable[begin].object = 0;
122 conditionHashTable[begin].condition.cvWaiters = 0;
123 conditionHashTable[begin].condition.mux = 0;
127 begin = CONDITION_HASH_SUCCESSOR(begin);
132 * Looks up an entry in the condition hash table.
135 conditionForObject (java_objectheader *object)
141 hashValue = CONDITION_HASH_VALUE(object);
142 while (conditionHashTable[hashValue].object != object
143 && conditionHashTable[hashValue].object != 0)
144 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
146 if (conditionHashTable[hashValue].object == 0)
153 return &conditionHashTable[hashValue].condition;
157 * Adds a new entry in the condition hash table and returns a pointer to the condition
160 addConditionForObject (java_objectheader *object)
166 hashValue = CONDITION_HASH_VALUE(object);
167 while (conditionHashTable[hashValue].object != 0)
168 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
170 conditionHashTable[hashValue].object = object;
174 return &conditionHashTable[hashValue].condition;
178 * Removes an entry from the condition hash table.
181 removeConditionForObject (java_objectheader *object)
187 hashValue = CONDITION_HASH_VALUE(object);
188 while (conditionHashTable[hashValue].object != object)
189 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
191 conditionHashTable[hashValue].object = 0;
192 conditionHashTable[hashValue].condition.cvWaiters = 0;
193 conditionHashTable[hashValue].condition.mux = 0;
195 reorderConditionHashTable(CONDITION_HASH_SUCCESSOR(hashValue));
201 * Returns the mutex entry for the specified object and increments its conditionCount.
204 conditionLockedMutexForObject (java_objectheader *object)
207 mutexHashEntry *entry;
213 hashValue = MUTEX_HASH_VALUE(object);
214 entry = &mutexHashTable[hashValue];
216 if (entry->object != 0)
218 if (entry->mutex.count == 0 && entry->conditionCount == 0)
221 entry->mutex.holder = 0;
222 entry->mutex.count = 0;
223 entry->mutex.muxWaiters = 0;
227 while (entry->next != 0 && entry->object != object)
230 if (entry->object != object)
232 entry->next = firstFreeOverflowEntry;
233 firstFreeOverflowEntry = firstFreeOverflowEntry->next;
238 assert(entry->conditionCount == 0);
243 if (entry->object == 0)
244 entry->object = object;
246 ++entry->conditionCount;
254 * Wait for the condition of an object to be signalled
257 wait_cond_for_object (java_objectheader *obj, s8 time)
260 mutexHashEntry *mutexEntry;
264 mutexEntry = conditionLockedMutexForObject(obj);
266 condition = conditionForObject(obj);
268 condition = addConditionForObject(obj);
270 DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
272 internal_wait_cond(&mutexEntry->mutex, condition, time);
274 if (condition->cvWaiters == 0 && condition->mux == 0)
275 removeConditionForObject(obj);
276 --mutexEntry->conditionCount;
282 * Signal the condition of an object
285 signal_cond_for_object (java_objectheader *obj)
291 condition = conditionForObject(obj);
293 condition = addConditionForObject(obj);
295 DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
297 internal_signal_cond(condition);
299 if (condition->cvWaiters == 0 && condition->mux == 0)
300 removeConditionForObject(obj);
306 * Broadcast the condition of an object.
309 broadcast_cond_for_object (java_objectheader *obj)
312 internal_broadcast_cond_for_object(obj);
317 * Internal: Broadcast the condition of an object.
320 internal_broadcast_cond_for_object (java_objectheader *obj)
324 condition = conditionForObject(obj);
326 condition = addConditionForObject(obj);
328 internal_broadcast_cond(condition);
330 if (condition->cvWaiters == 0 && condition->mux == 0)
331 removeConditionForObject(obj);
338 lock_mutex (iMux *mux)
341 internal_lock_mutex(mux);
346 * Lock the mutex for an object.
349 lock_mutex_for_object (java_objectheader *obj)
352 internal_lock_mutex_for_object(obj);
360 unlock_mutex (iMux *mux)
363 internal_unlock_mutex(mux);
368 * Unlock the mutex for an object.
371 unlock_mutex_for_object (java_objectheader *obj)
374 internal_unlock_mutex_for_object(obj);
379 * Wait on a condition variable.
382 wait_cond (iMux *mux, iCv *cond, s8 timeout)
385 internal_wait_cond(mux, cond, timeout);
390 * Signal a condition variable.
393 signal_cond (iCv *cond)
396 internal_signal_cond(cond);
401 * Broadcast a condition variable.
404 broadcast_cond (iCv *cond)
407 internal_broadcast_cond(cond);
412 * Internal: Lock a mutex.
415 internal_lock_mutex(iMux* mux)
417 assert(blockInts > 0);
419 if (mux->holder == 0)
421 mux->holder = currentThread;
423 DBG( fprintf(stderr, "set holder of %p to %p\n", mux, mux->holder); )
425 else if (mux->holder == currentThread)
431 while (mux->holder != 0)
433 suspendOnQThread(currentThread, &mux->muxWaiters);
435 mux->holder = currentThread;
441 * Internal: Release a mutex.
444 internal_unlock_mutex(iMux* mux)
448 assert(blockInts > 0);
450 assert(mux->holder == currentThread);
456 if (mux->muxWaiters != 0)
458 tid = mux->muxWaiters;
459 mux->muxWaiters = tid->next;
466 * Internal: Wait on a conditional variable.
467 * (timeout currently ignored)
470 internal_wait_cond(iMux* mux, iCv* cv, s8 timeout)
475 DBG( fprintf(stderr, "waiting on %p\n", cv); );
477 if (mux->holder != currentThread) {
478 *exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException);
481 assert(blockInts > 0);
488 /* If there's anyone waiting here, wake them up */
489 if (mux->muxWaiters != 0) {
490 tid = mux->muxWaiters;
491 mux->muxWaiters = tid->next;
495 /* Suspend, and keep suspended until I re-get the lock */
496 suspendOnQThread(currentThread, &cv->cvWaiters);
497 while (mux->holder != 0) {
498 DBG( fprintf(stderr, "woke up\n"); );
499 suspendOnQThread(currentThread, &mux->muxWaiters);
502 mux->holder = currentThread;
507 * Internal: Wake one thread on a conditional variable.
510 internal_signal_cond (iCv* cv)
514 DBG( fprintf(stderr, "signalling on %p\n", cv); );
516 /* If 'mux' isn't set then we've never waited on this object. */
521 if (cv->mux->holder != currentThread) {
522 *exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException);
525 assert(blockInts > 0);
527 /* Remove one thread from cv list */
528 if (cv->cvWaiters != 0) {
529 DBG( fprintf(stderr, "releasing a waiter\n"); );
532 cv->cvWaiters = tid->next;
534 /* Place it on mux list */
535 tid->next = cv->mux->muxWaiters;
536 cv->mux->muxWaiters = tid;
541 * Internal: Wake all threads on a conditional variable.
544 internal_broadcast_cond (iCv* cv)
548 /* If 'mux' isn't set then we've never waited on this object. */
553 if (cv->mux->holder != currentThread) {
554 *exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException);
557 assert(blockInts > 0);
559 /* Find the end of the cv list */
561 for (tidp = &cv->cvWaiters; *tidp != 0; tidp = &(*tidp)->next)
564 /* Place entire cv list on mux list */
565 (*tidp) = cv->mux->muxWaiters;
566 cv->mux->muxWaiters = cv->cvWaiters;