2 * Copyright (C) 2003, 2004, 2005, 2006, 2007
3 * Robert Lougher <rob@lougher.org.uk>.
5 * This file is part of JamVM.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2,
10 * or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
35 /* Trace lock operations and inflation/deflation */
37 #define TRACE(fmt, ...) jam_printf(fmt, ## __VA_ARGS__)
39 #define TRACE(fmt, ...)
44 #define HASHTABSZE 1<<5
45 #define PREPARE(obj) allocMonitor(obj)
46 #define HASH(obj) (getObjectHashcode(obj) >> LOG_OBJECT_GRAIN)
47 #define COMPARE(obj, mon, hash1, hash2) hash1 == hash2 && mon->obj == obj
50 LOCKWORD_COMPARE_AND_SWAP(&ptr->entering, UN_USED, 0); \
54 /* lockword format in "thin" mode
56 -------------------------------------------
57 | thread ID | count |0|
58 -------------------------------------------
61 lockword format in "fat" mode
63 -------------------------------------------
65 -------------------------------------------
72 #define COUNT_MASK (((1<<COUNT_SIZE)-1)<<COUNT_SHIFT)
74 #define TID_SHIFT (COUNT_SIZE+COUNT_SHIFT)
75 #define TID_SIZE (32-TID_SHIFT)
76 #define TID_MASK (((1<<TID_SIZE)-1)<<TID_SHIFT)
78 #define SCAVENGE(ptr) \
80 Monitor *mon = (Monitor *)ptr; \
81 char res = LOCKWORD_READ(&mon->entering) == UN_USED; \
83 TRACE("Scavenging monitor %p (obj %p)", mon, mon->obj); \
84 mon->next = mon_free_list; \
85 mon_free_list = mon; \
90 static Monitor
*mon_free_list
= NULL
;
91 static HashTable mon_cache
;
93 void monitorInit(Monitor
*mon
) {
94 memset(mon
, 0, sizeof(Monitor
));
95 pthread_mutex_init(&mon
->lock
, NULL
);
98 void waitSetAppend(Monitor
*mon
, Thread
*thread
) {
99 if(mon
->wait_set
== NULL
)
100 mon
->wait_set
= thread
->wait_prev
= thread
;
102 thread
->wait_next
= mon
->wait_set
;
103 thread
->wait_prev
= mon
->wait_set
->wait_prev
;
104 thread
->wait_prev
->wait_next
= mon
->wait_set
->wait_prev
= thread
;
106 thread
->wait_id
= mon
->wait_count
++;
109 void waitSetUnlinkThread(Monitor
*mon
, Thread
*thread
) {
110 if(mon
->wait_set
== thread
)
111 if((mon
->wait_set
= mon
->wait_set
->wait_next
) == thread
)
112 mon
->wait_set
= NULL
;
114 thread
->wait_prev
->wait_next
= thread
->wait_next
;
115 thread
->wait_next
->wait_prev
= thread
->wait_prev
;
116 thread
->wait_prev
= thread
->wait_next
= NULL
;
119 Thread
*waitSetSignalNext(Monitor
*mon
) {
120 Thread
*thread
= mon
->wait_set
;
123 waitSetUnlinkThread(mon
, thread
);
124 pthread_cond_signal(&thread
->wait_cv
);
126 thread
->notify_id
= mon
->wait_count
;
132 void monitorLock(Monitor
*mon
, Thread
*self
) {
133 if(mon
->owner
== self
)
136 if(pthread_mutex_trylock(&mon
->lock
)) {
137 disableSuspend(self
);
139 self
->blocked_mon
= mon
;
140 self
->blocked_count
++;
141 self
->state
= BLOCKED
;
143 pthread_mutex_lock(&mon
->lock
);
145 self
->state
= RUNNING
;
146 self
->blocked_mon
= NULL
;
154 int monitorTryLock(Monitor
*mon
, Thread
*self
) {
155 if(mon
->owner
== self
)
158 if(pthread_mutex_trylock(&mon
->lock
))
166 void monitorUnlock(Monitor
*mon
, Thread
*self
) {
167 if(mon
->owner
== self
) {
168 if(mon
->count
== 0) {
170 pthread_mutex_unlock(&mon
->lock
);
176 int monitorWait0(Monitor
*mon
, Thread
*self
, long long ms
, int ns
, int locked
) {
177 char timed
= (ms
!= 0) || (ns
!= 0);
178 char interrupted
= FALSE
;
179 char timeout
= FALSE
;
183 if(mon
->owner
!= self
)
186 /* We own the monitor */
188 disableSuspend(self
);
190 /* Unlock the monitor. As it could be recursively
191 locked remember the recursion count */
192 old_count
= mon
->count
;
196 /* Counter used in thin-lock deflation */
199 self
->wait_mon
= mon
;
205 gettimeofday(&tv
, 0);
207 seconds
= tv
.tv_sec
+ ms
/1000;
208 ts
.tv_nsec
= (tv
.tv_usec
+ ((ms
%1000)*1000))*1000 + ns
;
210 if(ts
.tv_nsec
> 999999999L) {
212 ts
.tv_nsec
-= 1000000000L;
215 /* If the number of seconds is too large just set
216 it to the max value instead of truncating.
217 Depending on result, we may not wait at all */
218 ts
.tv_sec
= seconds
> LONG_MAX
? LONG_MAX
: seconds
;
220 self
->state
= TIMED_WAITING
;
222 self
->state
= locked
? BLOCKED
: WAITING
;
224 if(self
->interrupted
&& !locked
)
228 self
->blocked_count
++;
230 self
->waited_count
++;
232 self
->interrupting
= FALSE
;
234 /* Add the thread onto the end of the wait set */
235 waitSetAppend(mon
, self
);
237 while(self
->wait_next
!= NULL
&& !self
->interrupting
)
239 if((timeout
= (pthread_cond_timedwait(&self
->wait_cv
, &mon
->lock
, &ts
) == ETIMEDOUT
)))
242 /* On Linux/i386 systems using LinuxThreads, pthread_cond_timedwait is
243 * implemented using sigjmp/longjmp. This resets the fpu control word
244 * back to 64-bit precision. The macro is empty for sane platforms. */
248 pthread_cond_wait(&self
->wait_cv
, &mon
->lock
);
251 /* If we've been interrupted or timed-out, we will not have been
252 removed from the wait set. If we have, we must have been
253 notified afterwards. In this case, the notify has been lost,
254 and we must signal another thread */
256 if(self
->interrupting
|| timeout
) {
257 /* An interrupt after a timeout remains pending */
258 interrupted
= !(locked
|| timeout
);
260 if(self
->wait_next
!= NULL
)
261 waitSetUnlinkThread(mon
, self
);
263 /* Notify lost. Signal another thread only if it
264 was on the wait set at the time of the notify */
265 if(mon
->wait_set
!= NULL
&& mon
->wait_set
->wait_id
< self
->notify_id
) {
266 Thread
*thread
= waitSetSignalNext(mon
);
267 thread
->notify_id
= self
->notify_id
;
272 self
->state
= RUNNING
;
273 self
->wait_mon
= NULL
;
275 /* Restore the monitor owner and recursion count */
278 mon
->count
= old_count
;
284 self
->interrupted
= FALSE
;
285 signalException("java/lang/InterruptedException", NULL
);
291 int monitorNotify(Monitor
*mon
, Thread
*self
) {
292 if(mon
->owner
!= self
)
295 /* Signal the first thread in the wait set. This
296 is the thread which has been waiting the longest */
297 waitSetSignalNext(mon
);
302 int monitorNotifyAll(Monitor
*mon
, Thread
*self
) {
303 if(mon
->owner
!= self
)
306 /* Signal all threads in the wait set */
307 while(waitSetSignalNext(mon
) != NULL
);
312 Monitor
*allocMonitor(Object
*obj
) {
315 if(mon_free_list
!= NULL
) {
317 mon_free_list
= mon
->next
;
319 mon
= (Monitor
*)sysMalloc(sizeof(Monitor
));
323 /* No need to wrap in LOCKWORD_WRITE as no thread should
324 * be modifying it when it's on the free list */
329 Monitor
*findMonitor(Object
*obj
) {
330 uintptr_t lockword
= LOCKWORD_READ(&obj
->lock
);
332 if(lockword
& SHAPE_BIT
)
333 return (Monitor
*) (lockword
& ~SHAPE_BIT
);
336 /* Add if absent, scavenge, locked */
337 findHashEntry(mon_cache
, obj
, mon
, TRUE
, TRUE
, TRUE
);
342 static void inflate(Object
*obj
, Monitor
*mon
, Thread
*self
) {
343 TRACE("Thread %p is inflating obj %p...\n", self
, obj
);
345 monitorNotifyAll(mon
, self
);
346 LOCKWORD_WRITE(&obj
->lock
, (uintptr_t) mon
| SHAPE_BIT
);
349 void objectLock(Object
*obj
) {
350 Thread
*self
= threadSelf();
351 uintptr_t thin_locked
= self
->id
<<TID_SHIFT
;
352 uintptr_t entering
, lockword
;
355 TRACE("Thread %p lock on obj %p...\n", self
, obj
);
357 if(LOCKWORD_COMPARE_AND_SWAP(&obj
->lock
, 0, thin_locked
)) {
358 /* This barrier is not needed for the thin-locking implementation --
359 it's a requirement of the Java memory model. */
364 lockword
= LOCKWORD_READ(&obj
->lock
);
365 if((lockword
& (TID_MASK
|SHAPE_BIT
)) == thin_locked
) {
366 int count
= lockword
& COUNT_MASK
;
368 if(count
< (((1<<COUNT_SIZE
)-1)<<COUNT_SHIFT
))
369 LOCKWORD_WRITE(&obj
->lock
, lockword
+ (1<<COUNT_SHIFT
));
371 mon
= findMonitor(obj
);
372 monitorLock(mon
, self
);
373 inflate(obj
, mon
, self
);
374 mon
->count
= 1<<COUNT_SIZE
;
380 mon
= findMonitor(obj
);
383 if((entering
= LOCKWORD_READ(&mon
->entering
)) == UN_USED
)
386 if(!(LOCKWORD_COMPARE_AND_SWAP(&mon
->entering
, entering
, entering
+1)))
389 if(mon
->obj
!= obj
) {
390 while(entering
= LOCKWORD_READ(&mon
->entering
),
391 !(LOCKWORD_COMPARE_AND_SWAP(&mon
->entering
, entering
, entering
-1)));
395 monitorLock(mon
, self
);
397 while(entering
= LOCKWORD_READ(&mon
->entering
),
398 !(LOCKWORD_COMPARE_AND_SWAP(&mon
->entering
, entering
, entering
-1)));
400 while((LOCKWORD_READ(&obj
->lock
) & SHAPE_BIT
) == 0) {
403 if(LOCKWORD_COMPARE_AND_SWAP(&obj
->lock
, 0, thin_locked
))
404 inflate(obj
, mon
, self
);
406 monitorWait0(mon
, self
, 0, 0, TRUE
);
410 void objectUnlock(Object
*obj
) {
411 Thread
*self
= threadSelf();
412 uintptr_t lockword
= LOCKWORD_READ(&obj
->lock
);
413 uintptr_t thin_locked
= self
->id
<<TID_SHIFT
;
415 TRACE("Thread %p unlock on obj %p...\n", self
, obj
);
417 if(lockword
== thin_locked
) {
418 /* This barrier is not needed for the thin-locking implementation --
419 it's a requirement of the Java memory model. */
420 JMM_UNLOCK_MBARRIER();
421 LOCKWORD_WRITE(&obj
->lock
, 0);
423 /* Required by thin-locking mechanism. */
427 if(testFlcBit(obj
)) {
428 Monitor
*mon
= findMonitor(obj
);
430 if(!monitorTryLock(mon
, self
)) {
435 if(testFlcBit(obj
) && (mon
->obj
== obj
))
436 monitorNotify(mon
, self
);
438 monitorUnlock(mon
, self
);
441 if((lockword
& (TID_MASK
|SHAPE_BIT
)) == thin_locked
)
442 LOCKWORD_WRITE(&obj
->lock
, lockword
- (1<<COUNT_SHIFT
));
444 if((lockword
& SHAPE_BIT
) != 0) {
445 Monitor
*mon
= (Monitor
*) (lockword
& ~SHAPE_BIT
);
447 if((mon
->count
== 0) && (LOCKWORD_READ(&mon
->entering
) == 0) &&
448 (mon
->in_wait
== 0)) {
449 TRACE("Thread %p is deflating obj %p...\n", self
, obj
);
451 /* This barrier is not needed for the thin-locking implementation --
452 it's a requirement of the Java memory model. */
453 JMM_UNLOCK_MBARRIER();
455 LOCKWORD_WRITE(&obj
->lock
, 0);
456 LOCKWORD_COMPARE_AND_SWAP(&mon
->entering
, 0, UN_USED
);
459 monitorUnlock(mon
, self
);
464 void objectWait(Object
*obj
, long long ms
, int ns
) {
465 uintptr_t lockword
= LOCKWORD_READ(&obj
->lock
);
466 Thread
*self
= threadSelf();
469 TRACE("Thread %p Wait on obj %p...\n", self
, obj
);
471 if((lockword
& SHAPE_BIT
) == 0) {
472 int tid
= (lockword
&TID_MASK
)>>TID_SHIFT
;
473 if(tid
== self
->id
) {
474 mon
= findMonitor(obj
);
475 monitorLock(mon
, self
);
476 inflate(obj
, mon
, self
);
477 mon
->count
= (lockword
&COUNT_MASK
)>>COUNT_SHIFT
;
481 mon
= (Monitor
*) (lockword
& ~SHAPE_BIT
);
483 if(monitorWait(mon
, self
, ms
, ns
))
487 signalException("java/lang/IllegalMonitorStateException", "thread not owner");
490 void objectNotify(Object
*obj
) {
491 uintptr_t lockword
= LOCKWORD_READ(&obj
->lock
);
492 Thread
*self
= threadSelf();
494 TRACE("Thread %p Notify on obj %p...\n", self
, obj
);
496 if((lockword
& SHAPE_BIT
) == 0) {
497 int tid
= (lockword
&TID_MASK
)>>TID_SHIFT
;
501 Monitor
*mon
= (Monitor
*) (lockword
& ~SHAPE_BIT
);
502 if(monitorNotify(mon
, self
))
506 signalException("java/lang/IllegalMonitorStateException", "thread not owner");
509 void objectNotifyAll(Object
*obj
) {
510 uintptr_t lockword
= LOCKWORD_READ(&obj
->lock
);
511 Thread
*self
= threadSelf();
513 TRACE("Thread %p NotifyAll on obj %p...\n", self
, obj
);
515 if((lockword
& SHAPE_BIT
) == 0) {
516 int tid
= (lockword
&TID_MASK
)>>TID_SHIFT
;
520 Monitor
*mon
= (Monitor
*) (lockword
& ~SHAPE_BIT
);
521 if(monitorNotifyAll(mon
, self
))
525 signalException("java/lang/IllegalMonitorStateException", "thread not owner");
528 int objectLockedByCurrent(Object
*obj
) {
529 uintptr_t lockword
= LOCKWORD_READ(&obj
->lock
);
530 Thread
*self
= threadSelf();
532 if((lockword
& SHAPE_BIT
) == 0) {
533 int tid
= (lockword
&TID_MASK
)>>TID_SHIFT
;
537 Monitor
*mon
= (Monitor
*) (lockword
& ~SHAPE_BIT
);
538 if(mon
->owner
== self
)
544 void initialiseMonitor() {
545 /* Init hash table, create lock */
546 initHashTable(mon_cache
, HASHTABSZE
, TRUE
);
549 /* Heap compaction support */
551 #define ITERATE(ptr) { \
552 Monitor *mon = (Monitor*)ptr; \
553 if(isMarked(mon->obj)) \
554 threadReference(&mon->obj); \
557 void threadMonitorCache() {
558 hashIterate(mon_cache
);