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.
27 static classinfo *class_java_lang_IllegalMonitorStateException;
35 extern thread* currentThread;
37 #if defined(USE_INTERNAL_THREADS)
39 mutexHashEntry *mutexHashTable;
40 int mutexHashTableSize;
43 mutexHashEntry *mutexOverflowTable;
44 int mutexOverflowTableSize;
45 mutexHashEntry *firstFreeOverflowEntry = 0;
47 conditionHashEntry *conditionHashTable;
48 int conditionHashTableSize;
49 long conditionHashMask;
59 mutexHashTableSize = MUTEX_HASH_TABLE_SIZE;
60 mutexHashTable = (mutexHashEntry*)malloc(sizeof(mutexHashEntry) * mutexHashTableSize);
61 mutexHashMask = (mutexHashTableSize - 1) << 3;
63 for (i = 0; i < mutexHashTableSize; ++i)
65 mutexHashTable[i].object = 0;
66 mutexHashTable[i].mutex.holder = 0;
67 mutexHashTable[i].mutex.count = 0;
68 mutexHashTable[i].mutex.muxWaiters = 0;
69 mutexHashTable[i].conditionCount = 0;
70 mutexHashTable[i].next = 0;
73 mutexOverflowTableSize = MUTEX_OVERFLOW_TABLE_SIZE;
74 mutexOverflowTable = (mutexHashEntry*)malloc(sizeof(mutexHashEntry)
75 * mutexOverflowTableSize);
77 firstFreeOverflowEntry = &mutexOverflowTable[0];
79 for (i = 0; i < mutexOverflowTableSize; ++i)
81 mutexOverflowTable[i].object = 0;
82 mutexOverflowTable[i].mutex.holder = 0;
83 mutexOverflowTable[i].mutex.count = 0;
84 mutexOverflowTable[i].mutex.muxWaiters = 0;
85 mutexOverflowTable[i].conditionCount = 0;
86 mutexOverflowTable[i].next = &mutexOverflowTable[i + 1];
88 mutexOverflowTable[i - 1].next = 0;
90 conditionHashTableSize = CONDITION_HASH_TABLE_SIZE;
91 conditionHashTable = (conditionHashEntry*)malloc(sizeof(conditionHashEntry)
92 * conditionHashTableSize);
93 conditionHashMask = (conditionHashTableSize - 1) << 3;
95 for (i = 0; i < conditionHashTableSize; ++i)
97 conditionHashTable[i].object = 0;
98 conditionHashTable[i].condition.cvWaiters = 0;
99 conditionHashTable[i].condition.mux = 0;
102 /* Load exception classes */
103 class_java_lang_IllegalMonitorStateException =
104 loader_load(unicode_new_char("java/lang/IllegalMonitorStateException"));
108 * Reorders part of the condition hash table. Must be called after an entry has been deleted.
111 reorderConditionHashTable (int begin)
113 while (conditionHashTable[begin].object != 0)
115 int hashValue = CONDITION_HASH_VALUE(conditionHashTable[begin].object);
117 if (hashValue != begin)
119 while (conditionHashTable[hashValue].object != 0)
121 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
122 if (hashValue == begin)
125 if (hashValue != begin)
127 conditionHashTable[hashValue] = conditionHashTable[begin];
128 conditionHashTable[begin].object = 0;
129 conditionHashTable[begin].condition.cvWaiters = 0;
130 conditionHashTable[begin].condition.mux = 0;
134 begin = CONDITION_HASH_SUCCESSOR(begin);
139 * Looks up an entry in the condition hash table.
142 conditionForObject (java_objectheader *object)
148 hashValue = CONDITION_HASH_VALUE(object);
149 while (conditionHashTable[hashValue].object != object
150 && conditionHashTable[hashValue].object != 0)
151 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
153 if (conditionHashTable[hashValue].object == 0)
160 return &conditionHashTable[hashValue].condition;
164 * Adds a new entry in the condition hash table and returns a pointer to the condition
167 addConditionForObject (java_objectheader *object)
173 hashValue = CONDITION_HASH_VALUE(object);
174 while (conditionHashTable[hashValue].object != 0)
175 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
177 conditionHashTable[hashValue].object = object;
181 return &conditionHashTable[hashValue].condition;
185 * Removes an entry from the condition hash table.
188 removeConditionForObject (java_objectheader *object)
194 hashValue = CONDITION_HASH_VALUE(object);
195 while (conditionHashTable[hashValue].object != object)
196 hashValue = CONDITION_HASH_SUCCESSOR(hashValue);
198 conditionHashTable[hashValue].object = 0;
199 conditionHashTable[hashValue].condition.cvWaiters = 0;
200 conditionHashTable[hashValue].condition.mux = 0;
202 reorderConditionHashTable(CONDITION_HASH_SUCCESSOR(hashValue));
208 * Returns the mutex entry for the specified object and increments its conditionCount.
211 conditionLockedMutexForObject (java_objectheader *object)
214 mutexHashEntry *entry;
220 hashValue = MUTEX_HASH_VALUE(object);
221 entry = &mutexHashTable[hashValue];
223 if (entry->object != 0)
225 if (entry->mutex.count == 0 && entry->conditionCount == 0)
228 entry->mutex.holder = 0;
229 entry->mutex.count = 0;
230 entry->mutex.muxWaiters = 0;
234 while (entry->next != 0 && entry->object != object)
237 if (entry->object != object)
239 entry->next = firstFreeOverflowEntry;
240 firstFreeOverflowEntry = firstFreeOverflowEntry->next;
245 assert(entry->conditionCount == 0);
250 if (entry->object == 0)
251 entry->object = object;
253 ++entry->conditionCount;
261 * Wait for the condition of an object to be signalled
264 wait_cond_for_object (java_objectheader *obj, s8 time)
267 mutexHashEntry *mutexEntry;
271 mutexEntry = conditionLockedMutexForObject(obj);
273 condition = conditionForObject(obj);
275 condition = addConditionForObject(obj);
277 DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
279 internal_wait_cond(&mutexEntry->mutex, condition, time);
281 if (condition->cvWaiters == 0 && condition->mux == 0)
282 removeConditionForObject(obj);
283 --mutexEntry->conditionCount;
289 * Signal the condition of an object
292 signal_cond_for_object (java_objectheader *obj)
298 condition = conditionForObject(obj);
300 condition = addConditionForObject(obj);
302 DBG( fprintf(stderr, "condition of %p is %p\n", obj, condition); );
304 internal_signal_cond(condition);
306 if (condition->cvWaiters == 0 && condition->mux == 0)
307 removeConditionForObject(obj);
313 * Broadcast the condition of an object.
316 broadcast_cond_for_object (java_objectheader *obj)
319 internal_broadcast_cond_for_object(obj);
324 * Internal: Broadcast the condition of an object.
327 internal_broadcast_cond_for_object (java_objectheader *obj)
331 condition = conditionForObject(obj);
333 condition = addConditionForObject(obj);
335 internal_broadcast_cond(condition);
337 if (condition->cvWaiters == 0 && condition->mux == 0)
338 removeConditionForObject(obj);
345 lock_mutex (iMux *mux)
348 internal_lock_mutex(mux);
353 * Lock the mutex for an object.
356 lock_mutex_for_object (java_objectheader *obj)
359 internal_lock_mutex_for_object(obj);
367 unlock_mutex (iMux *mux)
370 internal_unlock_mutex(mux);
375 * Unlock the mutex for an object.
378 unlock_mutex_for_object (java_objectheader *obj)
381 internal_unlock_mutex_for_object(obj);
386 * Wait on a condition variable.
389 wait_cond (iMux *mux, iCv *cond, s8 timeout)
392 internal_wait_cond(mux, cond, timeout);
397 * Signal a condition variable.
400 signal_cond (iCv *cond)
403 internal_signal_cond(cond);
408 * Broadcast a condition variable.
411 broadcast_cond (iCv *cond)
414 internal_broadcast_cond(cond);
419 * Internal: Lock a mutex.
422 internal_lock_mutex(iMux* mux)
424 assert(blockInts == 1);
426 if (mux->holder == 0)
428 mux->holder = currentThread;
430 DBG( fprintf(stderr, "set holder of %p to %p\n", mux, mux->holder); )
432 else if (mux->holder == currentThread)
438 while (mux->holder != 0)
440 suspendOnQThread(currentThread, &mux->muxWaiters);
442 mux->holder = currentThread;
448 * Internal: Release a mutex.
451 internal_unlock_mutex(iMux* mux)
455 assert(blockInts == 1);
457 assert(mux->holder == currentThread);
463 if (mux->muxWaiters != 0)
465 tid = mux->muxWaiters;
466 mux->muxWaiters = tid->next;
473 * Internal: Wait on a conditional variable.
474 * (timeout currently ignored)
477 internal_wait_cond(iMux* mux, iCv* cv, s8 timeout)
482 DBG( fprintf(stderr, "waiting on %p\n", cv); );
484 if (mux->holder != currentThread) {
485 exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException);
488 assert(blockInts == 1);
495 /* If there's anyone waiting here, wake them up */
496 if (mux->muxWaiters != 0) {
497 tid = mux->muxWaiters;
498 mux->muxWaiters = tid->next;
502 /* Suspend, and keep suspended until I re-get the lock */
503 suspendOnQThread(currentThread, &cv->cvWaiters);
504 while (mux->holder != 0) {
505 DBG( fprintf(stderr, "woke up\n"); );
506 suspendOnQThread(currentThread, &mux->muxWaiters);
509 mux->holder = currentThread;
514 * Internal: Wake one thread on a conditional variable.
517 internal_signal_cond (iCv* cv)
521 DBG( fprintf(stderr, "signalling on %p\n", cv); );
523 /* If 'mux' isn't set then we've never waited on this object. */
528 if (cv->mux->holder != currentThread) {
529 exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException);
532 assert(blockInts == 1);
534 /* Remove one thread from cv list */
535 if (cv->cvWaiters != 0) {
536 DBG( fprintf(stderr, "releasing a waiter\n"); );
539 cv->cvWaiters = tid->next;
541 /* Place it on mux list */
542 tid->next = cv->mux->muxWaiters;
543 cv->mux->muxWaiters = tid;
548 * Internal: Wake all threads on a conditional variable.
551 internal_broadcast_cond (iCv* cv)
555 /* If 'mux' isn't set then we've never waited on this object. */
560 if (cv->mux->holder != currentThread) {
561 exceptionptr = native_new_and_init(class_java_lang_IllegalMonitorStateException);
564 assert(blockInts == 1);
566 /* Find the end of the cv list */
568 for (tidp = &cv->cvWaiters; *tidp != 0; tidp = &(*tidp)->next)
571 /* Place entire cv list on mux list */
572 (*tidp) = cv->mux->muxWaiters;
573 cv->mux->muxWaiters = cv->cvWaiters;