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 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;
98 * Reorders part of the condition hash table. Must be called after an entry has been deleted.
101 reorderConditionHashTable (int begin)
103 while (conditionHashTable[begin].object != 0)
105 int hashValue = CONDITION_HASH_VALUE(conditionHashTable[begin].object);
107 if (hashValue != begin)
109 while (conditionHashTable[hashValue].object != 0)
111 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
112 if (hashValue == begin)
115 if (hashValue != begin)
117 conditionHashTable[hashValue] = conditionHashTable[begin];
118 conditionHashTable[begin].object = 0;
119 conditionHashTable[begin].condition.cvWaiters = 0;
120 conditionHashTable[begin].condition.mux = 0;
124 begin = CONDITION_HASH_SUCCESSOR(begin);
129 * Looks up an entry in the condition hash table.
132 conditionForObject (java_objectheader *object)
138 hashValue = CONDITION_HASH_VALUE(object);
139 while (conditionHashTable[hashValue].object != object
140 && conditionHashTable[hashValue].object != 0)
141 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
143 if (conditionHashTable[hashValue].object == 0)
150 return &conditionHashTable[hashValue].condition;
154 * Adds a new entry in the condition hash table and returns a pointer to the condition
157 addConditionForObject (java_objectheader *object)
163 hashValue = CONDITION_HASH_VALUE(object);
164 while (conditionHashTable[hashValue].object != 0)
165 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
167 conditionHashTable[hashValue].object = object;
171 return &conditionHashTable[hashValue].condition;
175 * Removes an entry from the condition hash table.
178 removeConditionForObject (java_objectheader *object)
184 hashValue = CONDITION_HASH_VALUE(object);
185 while (conditionHashTable[hashValue].object != object)
186 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
188 conditionHashTable[hashValue].object = 0;
189 conditionHashTable[hashValue].condition.cvWaiters = 0;
190 conditionHashTable[hashValue].condition.mux = 0;
192 reorderConditionHashTable(CONDITION_HASH_SUCCESSOR(hashValue));
198 * Returns the mutex entry for the specified object and increments its conditionCount.
201 conditionLockedMutexForObject (java_objectheader *object)
204 mutexHashEntry *entry;
210 hashValue = MUTEX_HASH_VALUE(object);
211 entry = &mutexHashTable[hashValue];
213 if (entry->object != 0)
215 if (entry->mutex.count == 0 && entry->conditionCount == 0)
218 entry->mutex.holder = 0;
219 entry->mutex.count = 0;
220 entry->mutex.muxWaiters = 0;
224 while (entry->next != 0 && entry->object != object)
227 if (entry->object != object)
229 entry->next = firstFreeOverflowEntry;
230 firstFreeOverflowEntry = firstFreeOverflowEntry->next;
235 assert(entry->conditionCount == 0);
240 if (entry->object == 0)
241 entry->object = object;
243 ++entry->conditionCount;
251 * Wait for the condition of an object to be signalled
254 wait_cond_for_object (java_objectheader *obj, s8 time)
257 mutexHashEntry *mutexEntry;
261 mutexEntry = conditionLockedMutexForObject(obj);
263 condition = conditionForObject(obj);
265 condition = addConditionForObject(obj);
267 DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
269 internal_wait_cond(&mutexEntry->mutex, condition, time);
271 if (condition->cvWaiters == 0 && condition->mux == 0)
272 removeConditionForObject(obj);
273 --mutexEntry->conditionCount;
279 * Signal the condition of an object
282 signal_cond_for_object (java_objectheader *obj)
288 condition = conditionForObject(obj);
290 condition = addConditionForObject(obj);
292 DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
294 internal_signal_cond(condition);
296 if (condition->cvWaiters == 0 && condition->mux == 0)
297 removeConditionForObject(obj);
303 * Broadcast the condition of an object.
306 broadcast_cond_for_object (java_objectheader *obj)
309 internal_broadcast_cond_for_object(obj);
314 * Internal: Broadcast the condition of an object.
317 internal_broadcast_cond_for_object (java_objectheader *obj)
321 condition = conditionForObject(obj);
323 condition = addConditionForObject(obj);
325 internal_broadcast_cond(condition);
327 if (condition->cvWaiters == 0 && condition->mux == 0)
328 removeConditionForObject(obj);
335 lock_mutex (iMux *mux)
338 internal_lock_mutex(mux);
343 * Lock the mutex for an object.
346 lock_mutex_for_object (java_objectheader *obj)
349 internal_lock_mutex_for_object(obj);
357 unlock_mutex (iMux *mux)
360 internal_unlock_mutex(mux);
365 * Unlock the mutex for an object.
368 unlock_mutex_for_object (java_objectheader *obj)
371 internal_unlock_mutex_for_object(obj);
376 * Wait on a condition variable.
379 wait_cond (iMux *mux, iCv *cond, s8 timeout)
382 internal_wait_cond(mux, cond, timeout);
387 * Signal a condition variable.
390 signal_cond (iCv *cond)
393 internal_signal_cond(cond);
398 * Broadcast a condition variable.
401 broadcast_cond (iCv *cond)
404 internal_broadcast_cond(cond);
409 * Internal: Lock a mutex.
412 internal_lock_mutex(iMux* mux)
414 assert(blockInts > 0);
416 if (mux->holder == 0)
418 mux->holder = currentThread;
420 DBG( fprintf(stderr, "set holder of %p to %p\n", mux, mux->holder); )
422 else if (mux->holder == currentThread)
428 while (mux->holder != 0)
430 suspendOnQThread(currentThread, &mux->muxWaiters);
432 mux->holder = currentThread;
438 * Internal: Release a mutex.
441 internal_unlock_mutex(iMux* mux)
445 assert(blockInts > 0);
447 assert(mux->holder == currentThread);
453 if (mux->muxWaiters != 0)
455 tid = mux->muxWaiters;
456 mux->muxWaiters = tid->next;
463 * Internal: Wait on a conditional variable.
464 * (timeout currently ignored)
467 internal_wait_cond(iMux* mux, iCv* cv, s8 timeout)
472 DBG( fprintf(stderr, "waiting on %p\n", cv); );
474 if (mux->holder != currentThread) {
475 *exceptionptr = new_exception(string_java_lang_IllegalMonitorStateException);
478 assert(blockInts > 0);
485 /* If there's anyone waiting here, wake them up */
486 if (mux->muxWaiters != 0) {
487 tid = mux->muxWaiters;
488 mux->muxWaiters = tid->next;
492 /* Suspend, and keep suspended until I re-get the lock */
493 suspendOnQThread(currentThread, &cv->cvWaiters);
494 while (mux->holder != 0) {
495 DBG( fprintf(stderr, "woke up\n"); );
496 suspendOnQThread(currentThread, &mux->muxWaiters);
499 mux->holder = currentThread;
504 * Internal: Wake one thread on a conditional variable.
507 internal_signal_cond (iCv* cv)
511 DBG( fprintf(stderr, "signalling on %p\n", cv); );
513 /* If 'mux' isn't set then we've never waited on this object. */
518 if (cv->mux->holder != currentThread) {
519 *exceptionptr = new_exception(string_java_lang_IllegalMonitorStateException);
522 assert(blockInts > 0);
524 /* Remove one thread from cv list */
525 if (cv->cvWaiters != 0) {
526 DBG( fprintf(stderr, "releasing a waiter\n"); );
529 cv->cvWaiters = tid->next;
531 /* Place it on mux list */
532 tid->next = cv->mux->muxWaiters;
533 cv->mux->muxWaiters = tid;
538 * Internal: Wake all threads on a conditional variable.
541 internal_broadcast_cond (iCv* cv)
545 /* If 'mux' isn't set then we've never waited on this object. */
550 if (cv->mux->holder != currentThread) {
551 *exceptionptr = new_exception(string_java_lang_IllegalMonitorStateException);
554 assert(blockInts > 0);
556 /* Find the end of the cv list */
558 for (tidp = &cv->cvWaiters; *tidp != 0; tidp = &(*tidp)->next)
561 /* Place entire cv list on mux list */
562 (*tidp) = cv->mux->muxWaiters;
563 cv->mux->muxWaiters = cv->cvWaiters;