--- a/src/JavaMonitor.st Tue Nov 22 10:12:20 2011 +0000
+++ b/src/JavaMonitor.st Tue Nov 22 12:04:31 2011 +0000
@@ -43,7 +43,8 @@
Object subclass:#JavaMonitor
instanceVariableNames:'owningProcess processesEntered monitorSema processesEnteredAccess
- owningProcessAccess count countAccess'
+ owningProcessAccess count countAccess waitingSema
+ processesWaitingAccess processesWaiting'
classVariableNames:''
poolDictionaries:''
category:'Languages-Java-Support'
@@ -160,6 +161,24 @@
"Created: / 20-11-2011 / 20:32:26 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
+processesWaitingAdd: aProcess
+ processesWaitingAccess
+ critical: [ self assert: (processesWaiting includesKey: aProcess) not.processesWaiting at: aProcess put: count ].
+
+ "Created: / 22-11-2011 / 11:57:50 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+!
+
+processesWaitingRestore: aProcess
+ processesWaitingAccess
+ critical: [
+ self assert: (processesWaiting includesKey: aProcess).
+ self reinitCounter: (processesWaiting at: aProcess).
+ processesWaiting removeKey: aProcess
+ ].
+
+ "Created: / 22-11-2011 / 12:59:14 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+!
+
reinitCounter
"owning process is different from previous, lets start counting from beginning"
@@ -168,8 +187,18 @@
"Created: / 22-11-2011 / 10:51:09 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
+reinitCounter: newCount
+ countAccess critical: [ count := newCount ].
+
+ "Created: / 22-11-2011 / 13:00:51 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+!
+
removeProcess: aProcess
- processesEnteredAccess critical: [ self assert: processesEntered last == aProcess. processesEntered remove: aProcess ].
+ processesEnteredAccess
+ critical: [
+ self assert: processesEntered last == aProcess.
+ processesEntered remove: aProcess
+ ].
"Created: / 20-11-2011 / 20:28:37 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !
@@ -183,6 +212,9 @@
processesEnteredAccess := Semaphore forMutualExclusion.
monitorSema := Semaphore new: 1.
countAccess := Semaphore forMutualExclusion.
+ processesWaiting := Dictionary new.
+ processesWaitingAccess := Semaphore forMutualExclusion.
+ waitingSema := Semaphore new: 0.
"Created: / 20-11-2011 / 13:28:28 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !
@@ -221,6 +253,28 @@
"Created: / 20-11-2011 / 13:21:54 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
+notify
+ "wakeup one waiting process"
+
+ | thisProcess |
+ thisProcess := Processor activeProcess.
+ self assert: (self isOwnedBy: thisProcess).
+ waitingSema signal.
+
+ "Created: / 22-11-2011 / 12:14:23 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+!
+
+notifyAll
+ "wakeup one waiting process"
+
+ | thisProcess |
+ thisProcess := Processor activeProcess.
+ self assert: (self isOwnedBy: thisProcess).
+ waitingSema signalForAll.
+
+ "Created: / 22-11-2011 / 12:14:36 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+!
+
release
| thisProcess |
thisProcess := self activeProcess.
@@ -233,6 +287,39 @@
]
"Created: / 20-11-2011 / 13:21:52 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+!
+
+releaseAll
+ count timesRepeat: [self release].
+
+ "Created: / 22-11-2011 / 13:05:20 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+!
+
+wait
+ "make owning process to go to wait"
+
+ self waitForMilliseconds: nil.
+
+ "Created: / 22-11-2011 / 11:57:56 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+!
+
+waitForMilliseconds: timeOut
+ "make owning process to go to wait, but not longer than timeout"
+
+ | thisProcess |
+ thisProcess := Processor activeProcess.
+ self assert: (self isOwnedBy: thisProcess).
+ self processesWaitingAdd: thisProcess.
+ self releaseAll.
+ waitingSema waitWithTimeoutMs: timeOut.
+ Logger
+ log: 'Process has been notified'
+ severity: #debug
+ facility: #JVM.
+ self acquire.
+ self processesWaitingRestore: thisProcess.
+
+ "Created: / 22-11-2011 / 12:52:45 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !
!JavaMonitor methodsFor:'queries'!
--- a/src/JavaMonitorsTests.st Tue Nov 22 10:12:20 2011 +0000
+++ b/src/JavaMonitorsTests.st Tue Nov 22 12:04:31 2011 +0000
@@ -42,7 +42,7 @@
"{ Package: 'stx:libjava' }"
TestCase subclass:#JavaMonitorsTests
- instanceVariableNames:'result reason thisProcess assertionAccess'
+ instanceVariableNames:'result reason thisProcess assertionAccess thisProcessAccess'
classVariableNames:''
poolDictionaries:''
category:'Languages-Java-Tests-Synchronization'
@@ -185,6 +185,7 @@
reason := 'Everything went just fine'.
thisProcess := Processor activeProcess.
assertionAccess := Semaphore forMutualExclusion.
+ thisProcessAccess := Semaphore forMutualExclusion.
"Created: / 20-11-2011 / 18:55:39 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
@@ -202,8 +203,8 @@
!
waitForAndResumeThisProcess
- self waitForStoppingThread: thisProcess.
- thisProcess resume.
+ thisProcessAccess critical: [self waitForStoppingThread: thisProcess.
+ thisProcess resume.]
"Created: / 20-11-2011 / 19:17:53 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!
@@ -300,12 +301,12 @@
t := [
count timesRepeat: [ mon enter ].
count timesRepeat: [
- self assert: (mon isOwnedBy: t).
+ self assert: (mon isOwnedBy: t) message: 'mon was not owned by t1'.
mon exit
].
self waitForAndResumeThisProcess
] newProcess.
- t resume.
+ t resume.
self stop.
self validateResult.
@@ -318,19 +319,17 @@
t1 := [
mon enter.
mon enter.
- self assert: (mon isOwnedBy: t1).
+ self assert: (mon isOwnedBy: t1) message: 'mon was not owned by t1 after multiple enter'.
mon exit.
t1 stop.
- self assert: (mon isOwnedBy: t1).
-
+ self assert: (mon isOwnedBy: t1) message:'mon was not owned by t1 after single exit'.
mon exit.
-
self waitForDyingThread: t2.
self waitForAndResumeThisProcess
] newProcess.
t2 := [
self waitForStoppingThread: t1.
- self assert: (mon isOwnedBy: t1).
+ self assert: (mon isOwnedBy: t1) message: 'mon was not owned by t1 after stop'.
t1 resume.
] newProcess.
t1 resume.
@@ -386,6 +385,137 @@
"Created: / 20-11-2011 / 14:51:22 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !
+!JavaMonitorsTests methodsFor:'wait notify tests'!
+
+testManyThreadsWaitNotifyAll
+ | mon threads |
+ mon := JavaMonitor new.
+ threads := OrderedCollection new.
+ 2 timesRepeat: [
+ | t |
+ t := [
+ mon enter.
+ self assert: (mon isOwnedBy: t)
+ message: 'thread was not owned by t after enter'.
+ self waitForAndResumeThisProcess.
+ 'resumed thisProcess' infoPrintCR.
+ mon wait.
+ 'notified and alive' infoPrintCR.
+ self assert: (mon isOwnedBy: t)
+ message: 'thread was not owned by t after wait'.
+ mon exit.
+ 'dying' infoPrintCR.
+ ] newProcess.
+ threads add: t.
+ ].
+ threads do: [
+ :each |
+ 'resuming t' infoPrintCR.
+ each resume
+ ].
+ threads do: [
+ :each |
+ 'stopping' infoPrintCR.
+ self stop
+ ].
+ threads do: [
+ :each |
+ 'waiting for waiting' infoPrintCR.
+ self waitForWaitingThread: each
+ ].
+ 'sync barrier reached' infoPrintCR.
+ mon enter.
+ mon notifyAll.
+ 'threads has been notified' infoPrintCR.
+ mon exit.
+ 'monitor exitted' infoPrintCR.
+ threads do: [
+ :each |
+ 'waiting for them to die' infoPrintCR.
+ self waitForDyingThread: each
+ ].
+ self validateResult.
+
+ "Created: / 22-11-2011 / 12:27:16 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+!
+
+testOneThreadWaitMultipleEnters
+ | mon t |
+ mon := JavaMonitor new.
+ t := [
+ mon enter.
+ mon enter.
+ mon enter.
+ self waitForAndResumeThisProcess.
+ self assert: (mon isOwnedBy: t)
+ message: 'thread was not owned by t after enter'.
+ mon wait.
+ self assert: (mon isOwnedBy: t)
+ message: 'thread was not owned by t after wait'.
+ mon exit.
+ self assert: (mon isOwnedBy: t)
+ message: 'thread was not owned by t after wait'.
+ mon exit.
+ self assert: (mon isOwnedBy: t)
+ message: 'thread was not owned by t after wait'.
+ mon exit.
+ ] newProcess.
+ t resume.
+ self stop.
+ mon enter.
+ mon notify.
+ mon exit.
+ self waitForDyingThread: t.
+ self validateResult.
+
+ "Created: / 22-11-2011 / 12:55:38 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+!
+
+testOneThreadWaitNotify
+ | mon t |
+ mon := JavaMonitor new.
+ t := [
+ mon enter.
+ self assert: (mon isOwnedBy: t)
+ message: 'thread was not owned by t after enter'.
+ self waitForAndResumeThisProcess.
+ mon wait.
+ self assert: (mon isOwnedBy: t)
+ message: 'thread was not owned by t after wait'.
+ self waitForAndResumeThisProcess
+ ] newProcess.
+ t resume.
+ self stop.
+ mon enter.
+ mon notify.
+ mon exit.
+ self stop.
+ self validateResult.
+
+ "Created: / 22-11-2011 / 11:51:28 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+!
+
+testOneThreadWaitTimeout
+ | mon t |
+ mon := JavaMonitor new.
+ t := [
+ mon enter.
+ self assert: (mon isOwnedBy: t)
+ message: 'thread was not owned by t after enter'.
+
+ "/notify will never come
+
+ mon waitForMilliseconds: 500.
+ self assert: (mon isOwnedBy: t)
+ message: 'thread was not owned by t after wait'.
+ ] newProcess.
+ t resume.
+ self waitForDyingThread: t.
+ self validateResult.
+
+ "Created: / 22-11-2011 / 12:51:13 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+! !
+
!JavaMonitorsTests class methodsFor:'documentation'!
version_SVN
--- a/src/stx_libjava.st Tue Nov 22 10:12:20 2011 +0000
+++ b/src/stx_libjava.st Tue Nov 22 12:04:31 2011 +0000
@@ -204,18 +204,18 @@
exclude individual packages in the #excludedFromPrerequisites method."
^ #(
- #'squeak:petitparser' "PPDelegateParser - superclass of JavaParser "
- #'stx:goodies/sunit' "TestCase - superclass of JavaMonitorsTests "
- #'stx:libbasic' "Array - superclass of JavaConstantPool "
- #'stx:libbasic2' "BitArray - superclass of extended BooleanArray "
+ #'squeak:petitparser' "PPCompositeParser - superclass of JavaParser "
+ #'stx:goodies/sunit' "TestAsserter - superclass of JavaMonitorsTests "
+ #'stx:libbasic' "PeekableStream - superclass of JavaParser::LineNumberStream "
+ #'stx:libbasic2' "Socket - superclass of JavaSocket "
#'stx:libbasic3' "MessageTracer - referenced by JavaMethod>>setBreakPoint "
#'stx:libcomp' "ObjectFileLoader - referenced by JavaVM class>>_Runtime_loadFileInternalI: "
#'stx:libhtml' "URL - referenced by JavaEmbeddedFrameView>>setupAppletFrameIn:initializeJava: "
- #'stx:libtool' "DebugView - referenced by Java class>>flushClasses "
- #'stx:libview' "GraphicsContext - superclass of JavaEmbeddedFrameView "
- #'stx:libview2' "GIFReader - referenced by JavaVM class>>_GifImageDecoder_parseImage: "
- #'stx:libwidg' "Button - referenced by JavaVM class>>_WButtonPeer_create: "
- #'stx:libwidg2' "ComboBoxView - referenced by JavaVM class>>processEvent: "
+ #'stx:libtool' "WorkspaceApplication - referenced by JavaEvaluator>>evaluate:in:receiver:notifying:logged:ifFail: "
+ #'stx:libview' "DeviceGraphicsContext - superclass of JavaPopUpView "
+ #'stx:libview2' "Plug - referenced by JavaSourceCodeCache>>findMethodLine:inMethods: "
+ #'stx:libwidg' "ScrollBar - referenced by JavaVM class>>_WScrollPanePeer__getVScrollbarWidth: "
+ #'stx:libwidg2' "CheckBox - referenced by JavaVM class>>_WCheckboxPeer_create: "
)
! !
@@ -574,6 +574,7 @@
'GenericToolbarIconLibrary class' javaRuntimeExceptionBrowserIcon
CharacterArray asDottedJavaClassName
CharacterArray asSlashedJavaClassName
+ Process isWaiting
)
! !
@@ -626,7 +627,7 @@
"Return a SVN revision number of myself.
This number is updated after a commit"
- ^ "$SVN-Revision:"'1496'"$"
+ ^ "$SVN-Revision:"'1498'"$"
! !
!stx_libjava class methodsFor:'file generation'!