Added API method `GDBDebugger >> send:andWithResultDo:`
authorJan Vrany <jan.vrany@fit.cvut.cz>
Fri, 26 Jan 2018 22:08:31 +0000
changeset 96 43591d874c9f
parent 95 f417138e9c48
child 97 b17c889076e4
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.
GDBDebugger.st
--- 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'!