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 #if !defined(NATIVE_THREADS)
30 static classinfo *class_java_lang_IllegalMonitorStateException;
32 extern thread* currentThread;
34 mutexHashEntry *mutexHashTable;
35 int mutexHashTableSize;
38 mutexHashEntry *mutexOverflowTable;
39 int mutexOverflowTableSize;
40 mutexHashEntry *firstFreeOverflowEntry = 0;
42 conditionHashEntry *conditionHashTable;
43 int conditionHashTableSize;
44 long conditionHashMask;
54 mutexHashTableSize = MUTEX_HASH_TABLE_SIZE;
55 mutexHashTable = (mutexHashEntry*)malloc(sizeof(mutexHashEntry) * mutexHashTableSize);
56 mutexHashMask = (mutexHashTableSize - 1) << 3;
58 for (i = 0; i < mutexHashTableSize; ++i)
60 mutexHashTable[i].object = 0;
61 mutexHashTable[i].mutex.holder = 0;
62 mutexHashTable[i].mutex.count = 0;
63 mutexHashTable[i].mutex.muxWaiters = 0;
64 mutexHashTable[i].conditionCount = 0;
65 mutexHashTable[i].next = 0;
68 mutexOverflowTableSize = MUTEX_OVERFLOW_TABLE_SIZE;
69 mutexOverflowTable = (mutexHashEntry*)malloc(sizeof(mutexHashEntry)
70 * mutexOverflowTableSize);
72 firstFreeOverflowEntry = &mutexOverflowTable[0];
74 for (i = 0; i < mutexOverflowTableSize; ++i)
76 mutexOverflowTable[i].object = 0;
77 mutexOverflowTable[i].mutex.holder = 0;
78 mutexOverflowTable[i].mutex.count = 0;
79 mutexOverflowTable[i].mutex.muxWaiters = 0;
80 mutexOverflowTable[i].conditionCount = 0;
81 mutexOverflowTable[i].next = &mutexOverflowTable[i + 1];
83 mutexOverflowTable[i - 1].next = 0;
85 conditionHashTableSize = CONDITION_HASH_TABLE_SIZE;
86 conditionHashTable = (conditionHashEntry*)malloc(sizeof(conditionHashEntry)
87 * conditionHashTableSize);
88 conditionHashMask = (conditionHashTableSize - 1) << 3;
90 for (i = 0; i < conditionHashTableSize; ++i)
92 conditionHashTable[i].object = 0;
93 conditionHashTable[i].condition.cvWaiters = 0;
94 conditionHashTable[i].condition.mux = 0;
97 /* Load exception classes */
98 loader_load_sysclass(&class_java_lang_IllegalMonitorStateException,
99 utf_new_char("java/lang/IllegalMonitorStateException"));
103 * Reorders part of the condition hash table. Must be called after an entry has been deleted.
106 reorderConditionHashTable (int begin)
108 while (conditionHashTable[begin].object != 0)
110 int hashValue = CONDITION_HASH_VALUE(conditionHashTable[begin].object);
112 if (hashValue != begin)
114 while (conditionHashTable[hashValue].object != 0)
116 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
117 if (hashValue == begin)
120 if (hashValue != begin)
122 conditionHashTable[hashValue] = conditionHashTable[begin];
123 conditionHashTable[begin].object = 0;
124 conditionHashTable[begin].condition.cvWaiters = 0;
125 conditionHashTable[begin].condition.mux = 0;
129 begin = CONDITION_HASH_SUCCESSOR(begin);
134 * Looks up an entry in the condition hash table.
137 conditionForObject (java_objectheader *object)
143 hashValue = CONDITION_HASH_VALUE(object);
144 while (conditionHashTable[hashValue].object != object
145 && conditionHashTable[hashValue].object != 0)
146 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
148 if (conditionHashTable[hashValue].object == 0)
155 return &conditionHashTable[hashValue].condition;
159 * Adds a new entry in the condition hash table and returns a pointer to the condition
162 addConditionForObject (java_objectheader *object)
168 hashValue = CONDITION_HASH_VALUE(object);
169 while (conditionHashTable[hashValue].object != 0)
170 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
172 conditionHashTable[hashValue].object = object;
176 return &conditionHashTable[hashValue].condition;
180 * Removes an entry from the condition hash table.
183 removeConditionForObject (java_objectheader *object)
189 hashValue = CONDITION_HASH_VALUE(object);
190 while (conditionHashTable[hashValue].object != object)
191 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
193 conditionHashTable[hashValue].object = 0;
194 conditionHashTable[hashValue].condition.cvWaiters = 0;
195 conditionHashTable[hashValue].condition.mux = 0;
197 reorderConditionHashTable(CONDITION_HASH_SUCCESSOR(hashValue));
203 * Returns the mutex entry for the specified object and increments its conditionCount.
206 conditionLockedMutexForObject (java_objectheader *object)
209 mutexHashEntry *entry;
215 hashValue = MUTEX_HASH_VALUE(object);
216 entry = &mutexHashTable[hashValue];
218 if (entry->object != 0)
220 if (entry->mutex.count == 0 && entry->conditionCount == 0)
223 entry->mutex.holder = 0;
224 entry->mutex.count = 0;
225 entry->mutex.muxWaiters = 0;
229 while (entry->next != 0 && entry->object != object)
232 if (entry->object != object)
234 entry->next = firstFreeOverflowEntry;
235 firstFreeOverflowEntry = firstFreeOverflowEntry->next;
240 assert(entry->conditionCount == 0);
245 if (entry->object == 0)
246 entry->object = object;
248 ++entry->conditionCount;
256 * Wait for the condition of an object to be signalled
259 wait_cond_for_object (java_objectheader *obj, s8 time)
262 mutexHashEntry *mutexEntry;
266 mutexEntry = conditionLockedMutexForObject(obj);
268 condition = conditionForObject(obj);
270 condition = addConditionForObject(obj);
272 DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
274 internal_wait_cond(&mutexEntry->mutex, condition, time);
276 if (condition->cvWaiters == 0 && condition->mux == 0)
277 removeConditionForObject(obj);
278 --mutexEntry->conditionCount;
284 * Signal the condition of an object
287 signal_cond_for_object (java_objectheader *obj)
293 condition = conditionForObject(obj);
295 condition = addConditionForObject(obj);
297 DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
299 internal_signal_cond(condition);
301 if (condition->cvWaiters == 0 && condition->mux == 0)
302 removeConditionForObject(obj);
308 * Broadcast the condition of an object.
311 broadcast_cond_for_object (java_objectheader *obj)
314 internal_broadcast_cond_for_object(obj);
319 * Internal: Broadcast the condition of an object.
322 internal_broadcast_cond_for_object (java_objectheader *obj)
326 condition = conditionForObject(obj);
328 condition = addConditionForObject(obj);
330 internal_broadcast_cond(condition);
332 if (condition->cvWaiters == 0 && condition->mux == 0)
333 removeConditionForObject(obj);
340 lock_mutex (iMux *mux)
343 internal_lock_mutex(mux);
348 * Lock the mutex for an object.
351 lock_mutex_for_object (java_objectheader *obj)
354 internal_lock_mutex_for_object(obj);
362 unlock_mutex (iMux *mux)
365 internal_unlock_mutex(mux);
370 * Unlock the mutex for an object.
373 unlock_mutex_for_object (java_objectheader *obj)
376 internal_unlock_mutex_for_object(obj);
381 * Wait on a condition variable.
384 wait_cond (iMux *mux, iCv *cond, s8 timeout)
387 internal_wait_cond(mux, cond, timeout);
392 * Signal a condition variable.
395 signal_cond (iCv *cond)
398 internal_signal_cond(cond);
403 * Broadcast a condition variable.
406 broadcast_cond (iCv *cond)
409 internal_broadcast_cond(cond);
414 * Internal: Lock a mutex.
417 internal_lock_mutex(iMux* mux)
419 assert(blockInts > 0);
421 if (mux->holder == 0)
423 mux->holder = currentThread;
425 DBG( fprintf(stderr, "set holder of %p to %p\n", mux, mux->holder); )
427 else if (mux->holder == currentThread)
433 while (mux->holder != 0)
435 suspendOnQThread(currentThread, &mux->muxWaiters);
437 mux->holder = currentThread;
443 * Internal: Release a mutex.
446 internal_unlock_mutex(iMux* mux)
450 assert(blockInts > 0);
452 assert(mux->holder == currentThread);
458 if (mux->muxWaiters != 0)
460 tid = mux->muxWaiters;
461 mux->muxWaiters = tid->next;
468 * Internal: Wait on a conditional variable.
469 * (timeout currently ignored)
472 internal_wait_cond(iMux* mux, iCv* cv, s8 timeout)
477 DBG( fprintf(stderr, "waiting on %p\n", cv); );
479 if (mux->holder != currentThread) {
480 *exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException);
483 assert(blockInts > 0);
490 /* If there's anyone waiting here, wake them up */
491 if (mux->muxWaiters != 0) {
492 tid = mux->muxWaiters;
493 mux->muxWaiters = tid->next;
497 /* Suspend, and keep suspended until I re-get the lock */
498 suspendOnQThread(currentThread, &cv->cvWaiters);
499 while (mux->holder != 0) {
500 DBG( fprintf(stderr, "woke up\n"); );
501 suspendOnQThread(currentThread, &mux->muxWaiters);
504 mux->holder = currentThread;
509 * Internal: Wake one thread on a conditional variable.
512 internal_signal_cond (iCv* cv)
516 DBG( fprintf(stderr, "signalling on %p\n", cv); );
518 /* If 'mux' isn't set then we've never waited on this object. */
523 if (cv->mux->holder != currentThread) {
524 *exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException);
527 assert(blockInts > 0);
529 /* Remove one thread from cv list */
530 if (cv->cvWaiters != 0) {
531 DBG( fprintf(stderr, "releasing a waiter\n"); );
534 cv->cvWaiters = tid->next;
536 /* Place it on mux list */
537 tid->next = cv->mux->muxWaiters;
538 cv->mux->muxWaiters = tid;
543 * Internal: Wake all threads on a conditional variable.
546 internal_broadcast_cond (iCv* cv)
550 /* If 'mux' isn't set then we've never waited on this object. */
555 if (cv->mux->holder != currentThread) {
556 *exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException);
559 assert(blockInts > 0);
561 /* Find the end of the cv list */
563 for (tidp = &cv->cvWaiters; *tidp != 0; tidp = &(*tidp)->next)
566 /* Place entire cv list on mux list */
567 (*tidp) = cv->mux->muxWaiters;
568 cv->mux->muxWaiters = cv->cvWaiters;