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.
21 #include "../tables.h"
22 #include "../native.h"
23 #include "../loader.h"
25 static classinfo *class_java_lang_IllegalMonitorStateException;
33 extern thread* currentThread;
35 #if defined(USE_INTERNAL_THREADS)
37 mutexHashEntry *mutexHashTable;
38 int mutexHashTableSize;
41 mutexHashEntry *mutexOverflowTable;
42 int mutexOverflowTableSize;
43 mutexHashEntry *firstFreeOverflowEntry = 0;
45 conditionHashEntry *conditionHashTable;
46 int conditionHashTableSize;
47 long conditionHashMask;
57 mutexHashTableSize = MUTEX_HASH_TABLE_SIZE;
58 mutexHashTable = (mutexHashEntry*)malloc(sizeof(mutexHashEntry) * mutexHashTableSize);
59 mutexHashMask = (mutexHashTableSize - 1) << 3;
61 for (i = 0; i < mutexHashTableSize; ++i)
63 mutexHashTable[i].object = 0;
64 mutexHashTable[i].mutex.holder = 0;
65 mutexHashTable[i].mutex.count = 0;
66 mutexHashTable[i].mutex.muxWaiters = 0;
67 mutexHashTable[i].conditionCount = 0;
68 mutexHashTable[i].next = 0;
71 mutexOverflowTableSize = MUTEX_OVERFLOW_TABLE_SIZE;
72 mutexOverflowTable = (mutexHashEntry*)malloc(sizeof(mutexHashEntry)
73 * mutexOverflowTableSize);
75 firstFreeOverflowEntry = &mutexOverflowTable[0];
77 for (i = 0; i < mutexOverflowTableSize; ++i)
79 mutexOverflowTable[i].object = 0;
80 mutexOverflowTable[i].mutex.holder = 0;
81 mutexOverflowTable[i].mutex.count = 0;
82 mutexOverflowTable[i].mutex.muxWaiters = 0;
83 mutexOverflowTable[i].conditionCount = 0;
84 mutexOverflowTable[i].next = &mutexOverflowTable[i + 1];
86 mutexOverflowTable[i - 1].next = 0;
88 conditionHashTableSize = CONDITION_HASH_TABLE_SIZE;
89 conditionHashTable = (conditionHashEntry*)malloc(sizeof(conditionHashEntry)
90 * conditionHashTableSize);
91 conditionHashMask = (conditionHashTableSize - 1) << 3;
93 for (i = 0; i < conditionHashTableSize; ++i)
95 conditionHashTable[i].object = 0;
96 conditionHashTable[i].condition.cvWaiters = 0;
97 conditionHashTable[i].condition.mux = 0;
100 /* Load exception classes */
101 class_java_lang_IllegalMonitorStateException =
102 loader_load(unicode_new_char("java/lang/IllegalMonitorStateException"));
106 * Reorders part of the condition hash table. Must be called after an entry has been deleted.
109 reorderConditionHashTable (int begin)
111 while (conditionHashTable[begin].object != 0)
113 int hashValue = CONDITION_HASH_VALUE(conditionHashTable[begin].object);
115 if (hashValue != begin)
117 while (conditionHashTable[hashValue].object != 0)
119 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
120 if (hashValue == begin)
123 if (hashValue != begin)
125 conditionHashTable[hashValue] = conditionHashTable[begin];
126 conditionHashTable[begin].object = 0;
127 conditionHashTable[begin].condition.cvWaiters = 0;
128 conditionHashTable[begin].condition.mux = 0;
132 begin = CONDITION_HASH_SUCCESSOR(begin);
137 * Looks up an entry in the condition hash table.
140 conditionForObject (java_objectheader *object)
146 hashValue = CONDITION_HASH_VALUE(object);
147 while (conditionHashTable[hashValue].object != object
148 && conditionHashTable[hashValue].object != 0)
149 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
151 if (conditionHashTable[hashValue].object == 0)
158 return &conditionHashTable[hashValue].condition;
162 * Adds a new entry in the condition hash table and returns a pointer to the condition
165 addConditionForObject (java_objectheader *object)
171 hashValue = CONDITION_HASH_VALUE(object);
172 while (conditionHashTable[hashValue].object != 0)
173 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
175 conditionHashTable[hashValue].object = object;
179 return &conditionHashTable[hashValue].condition;
183 * Removes an entry from the condition hash table.
186 removeConditionForObject (java_objectheader *object)
192 hashValue = CONDITION_HASH_VALUE(object);
193 while (conditionHashTable[hashValue].object != object)
194 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
196 conditionHashTable[hashValue].object = 0;
197 conditionHashTable[hashValue].condition.cvWaiters = 0;
198 conditionHashTable[hashValue].condition.mux = 0;
200 reorderConditionHashTable(CONDITION_HASH_SUCCESSOR(hashValue));
206 * Returns the mutex entry for the specified object and increments its conditionCount.
209 conditionLockedMutexForObject (java_objectheader *object)
212 mutexHashEntry *entry;
218 hashValue = MUTEX_HASH_VALUE(object);
219 entry = &mutexHashTable[hashValue];
221 if (entry->object != 0)
223 if (entry->mutex.count == 0 && entry->conditionCount == 0)
226 entry->mutex.holder = 0;
227 entry->mutex.count = 0;
228 entry->mutex.muxWaiters = 0;
232 while (entry->next != 0 && entry->object != object)
235 if (entry->object != object)
237 entry->next = firstFreeOverflowEntry;
238 firstFreeOverflowEntry = firstFreeOverflowEntry->next;
243 assert(entry->conditionCount == 0);
248 if (entry->object == 0)
249 entry->object = object;
251 ++entry->conditionCount;
259 * Wait for the condition of an object to be signalled
262 wait_cond_for_object (java_objectheader *obj, s8 time)
265 mutexHashEntry *mutexEntry;
269 mutexEntry = conditionLockedMutexForObject(obj);
271 condition = conditionForObject(obj);
273 condition = addConditionForObject(obj);
275 DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
277 internal_wait_cond(&mutexEntry->mutex, condition, time);
279 if (condition->cvWaiters == 0 && condition->mux == 0)
280 removeConditionForObject(obj);
281 --mutexEntry->conditionCount;
287 * Signal the condition of an object
290 signal_cond_for_object (java_objectheader *obj)
296 condition = conditionForObject(obj);
298 condition = addConditionForObject(obj);
300 DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
302 internal_signal_cond(condition);
304 if (condition->cvWaiters == 0 && condition->mux == 0)
305 removeConditionForObject(obj);
311 * Broadcast the condition of an object.
314 broadcast_cond_for_object (java_objectheader *obj)
317 internal_broadcast_cond_for_object(obj);
322 * Internal: Broadcast the condition of an object.
325 internal_broadcast_cond_for_object (java_objectheader *obj)
329 condition = conditionForObject(obj);
331 condition = addConditionForObject(obj);
333 internal_broadcast_cond(condition);
335 if (condition->cvWaiters == 0 && condition->mux == 0)
336 removeConditionForObject(obj);
343 lock_mutex (iMux *mux)
346 internal_lock_mutex(mux);
351 * Lock the mutex for an object.
354 lock_mutex_for_object (java_objectheader *obj)
357 internal_lock_mutex_for_object(obj);
365 unlock_mutex (iMux *mux)
368 internal_unlock_mutex(mux);
373 * Unlock the mutex for an object.
376 unlock_mutex_for_object (java_objectheader *obj)
379 internal_unlock_mutex_for_object(obj);
384 * Wait on a condition variable.
387 wait_cond (iMux *mux, iCv *cond, s8 timeout)
390 internal_wait_cond(mux, cond, timeout);
395 * Signal a condition variable.
398 signal_cond (iCv *cond)
401 internal_signal_cond(cond);
406 * Broadcast a condition variable.
409 broadcast_cond (iCv *cond)
412 internal_broadcast_cond(cond);
417 * Internal: Lock a mutex.
420 internal_lock_mutex(iMux* mux)
422 assert(blockInts == 1);
424 if (mux->holder == 0)
426 mux->holder = currentThread;
428 DBG( fprintf(stderr, "set holder of %p to %p\n", mux, mux->holder); )
430 else if (mux->holder == currentThread)
436 while (mux->holder != 0)
438 suspendOnQThread(currentThread, &mux->muxWaiters);
440 mux->holder = currentThread;
446 * Internal: Release a mutex.
449 internal_unlock_mutex(iMux* mux)
453 assert(blockInts == 1);
455 assert(mux->holder == currentThread);
461 if (mux->muxWaiters != 0)
463 tid = mux->muxWaiters;
464 mux->muxWaiters = tid->next;
471 * Internal: Wait on a conditional variable.
472 * (timeout currently ignored)
475 internal_wait_cond(iMux* mux, iCv* cv, s8 timeout)
480 DBG( fprintf(stderr, "waiting on %p\n", cv); );
482 if (mux->holder != currentThread) {
483 exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException);
486 assert(blockInts == 1);
493 /* If there's anyone waiting here, wake them up */
494 if (mux->muxWaiters != 0) {
495 tid = mux->muxWaiters;
496 mux->muxWaiters = tid->next;
500 /* Suspend, and keep suspended until I re-get the lock */
501 suspendOnQThread(currentThread, &cv->cvWaiters);
502 while (mux->holder != 0) {
503 DBG( fprintf(stderr, "woke up\n"); );
504 suspendOnQThread(currentThread, &mux->muxWaiters);
507 mux->holder = currentThread;
512 * Internal: Wake one thread on a conditional variable.
515 internal_signal_cond (iCv* cv)
519 DBG( fprintf(stderr, "signalling on %p\n", cv); );
521 /* If 'mux' isn't set then we've never waited on this object. */
526 if (cv->mux->holder != currentThread) {
527 exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException);
530 assert(blockInts == 1);
532 /* Remove one thread from cv list */
533 if (cv->cvWaiters != 0) {
534 DBG( fprintf(stderr, "releasing a waiter\n"); );
537 cv->cvWaiters = tid->next;
539 /* Place it on mux list */
540 tid->next = cv->mux->muxWaiters;
541 cv->mux->muxWaiters = tid;
546 * Internal: Wake all threads on a conditional variable.
549 internal_broadcast_cond (iCv* cv)
553 /* If 'mux' isn't set then we've never waited on this object. */
558 if (cv->mux->holder != currentThread) {
559 exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException);
562 assert(blockInts == 1);
564 /* Find the end of the cv list */
566 for (tidp = &cv->cvWaiters; *tidp != 0; tidp = &(*tidp)->next)
569 /* Place entire cv list on mux list */
570 (*tidp) = cv->mux->muxWaiters;
571 cv->mux->muxWaiters = cv->cvWaiters;