Added API method `GDBDebugger >> send:andWithResultDo:`
that sends the command asynchronously and calls back passed
block once command finishes. This is useful for e.g. UI code
to issue a command and handle the result without blocking
the UI until command finishes.
--- a/GDBDebugger.st Thu Jan 11 23:53:06 2018 +0000
+++ b/GDBDebugger.st Fri Jan 26 22:08:31 2018 +0000
@@ -196,32 +196,14 @@
be parsed into a GDBCommand.
"
- | cmd token blocker handler1 handler2 result |
+ | blocker result |
- cmd := command.
- cmd isString ifTrue:[
- cmd := GDBCLICommand new value:cmd.
- ].
- token := self nextCommandSequnceNumber.
- cmd token:token.
^ wait ifTrue:[
- self assert:Processor activeProcess ~~ connection eventDispatchProcess
- message:'Cannot send commands from within event dispatching process. Would deadlock'.
- handler1 := [:ev |
- ev token == token ifTrue:[
- connection eventAnnouncer unsubscribe:handler1.
- result := ev result.
- connection eventAnnouncerInternal when:GDBEventSetProcessingFinished
- do:handler2.
- ]
+ blocker := Semaphore new.
+ self send: command andWithResultDo: [ :r |
+ result := r.
+ blocker signal
].
- handler2 := [:ev |
- connection eventAnnouncerInternal unsubscribe:handler2.
- blocker signal.
- ].
- blocker := Semaphore new.
- connection eventAnnouncer when:GDBCommandResultEvent do:handler1.
- connection pushEvent:(GDBCommandEvent new command:cmd).
blocker wait.
result isError ifTrue:[
GDBCommandFailedError raiseForResult: result.
@@ -229,12 +211,18 @@
result.
]
ifFalse:[
+ | cmd |
+
+ cmd := command.
+ cmd isString ifTrue:[
+ cmd := GDBCLICommand new value:cmd.
+ ].
connection pushEvent:(GDBCommandEvent new command:cmd).
nil.
]
"Created: / 02-06-2014 / 23:45:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
- "Modified: / 13-09-2017 / 14:46:12 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 26-01-2018 / 21:52:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
send:command andWaitFor:eventHandlers
@@ -297,6 +285,56 @@
"Created: / 07-03-2015 / 11:38:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 08-03-2015 / 07:31:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+send:command andWithResultDo: block
+ "Sends given `command` to GDB and return nil immediately. Once the command
+ is processed and result returned, evaluate `block` passing the
+ result (as instance of GDBCommandResult)
+
+ The `command` may be either a GDBCommand or string, in which case it will
+ be parsed into a GDBCommand.
+
+ When calling this method from a UI code, i.e., from an UI even loop, keep
+ in mind that the block will be evaluated from within GDB's internal event
+ dispatch loop.
+
+ It's is a gooc practice not to do anything real within the block but just
+ grab the result and lt it processed within UI event loop, e.g.
+
+ doSomeAction
+
+ debugger send: (GDBMI_data_read_memory arguments:...)
+ andWithResultDo:[ :result | self sensor pushUserEvent: #updateWithReslt: with: result ].
+ "
+
+ | cmd token handler1 handler2 result |
+
+ cmd := command.
+ cmd isString ifTrue:[
+ cmd := GDBCLICommand new value:cmd.
+ ].
+ token := self nextCommandSequnceNumber.
+ cmd token:token.
+ self assert:Processor activeProcess ~~ connection eventDispatchProcess
+ message:'Cannot send commands from within event dispatching process. Would deadlock'.
+ handler1 := [:ev |
+ ev token == token ifTrue:[
+ connection eventAnnouncer unsubscribe:handler1.
+ result := ev result.
+ connection eventAnnouncerInternal when:GDBEventSetProcessingFinished
+ do:handler2.
+ ]
+ ].
+ handler2 := [:ev |
+ connection eventAnnouncerInternal unsubscribe:handler2.
+ block value: result.
+ ].
+ connection eventAnnouncer when:GDBCommandResultEvent do:handler1.
+ connection pushEvent:(GDBCommandEvent new command:cmd).
+ ^ nil
+
+ "Created: / 26-01-2018 / 21:47:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!GDBDebugger methodsFor:'commands - API'!