Lisp HUG Maillist Archive

LW 4.2 on Linux, multiprocessing w/ capi


I have a capi app that receives a stream of UDP packets, each of which
is "pretty printed" to a separate grid-pane, multiple grid-panes being
organized under a tab-pane.  There are several tab-panes thus composed,
the user is able to select which is displayed.  The idea is the user can
observe the contents of the latest of several kinds of packets from
several different senders.

The udp packet processor runs as a separate process, updating the
display via execute-with-interface.  All that works fine.

I need to add a 1 sec timer to form the basis of rate stats.  The timer
runs OK but when get an error when I update a title-pane with the stats
(again using execute-with-interface), and the interface happens to be
busy re-arranging the display (the user having selected a different tab
& grid to display).  The error seems to be occur only when the interface
is spending a lot of time recomputing the display (the grid panes are
each composed of hundreds of rows of title-panes and several grid-panes
per tab-pane- lots of geometry math).

The error is a "PROCESS-WAIT called when scheduling not allowed"
condition in the timer routine.  When aborted, the timer does not
reschedule but the rest of the interface functions normally.  

I've tried manually rescheduling the timer after the
execute-with-interface returns, does not affect the problem.

I've tried my own with-lock's and execute-without-preemption's around
the execute-with-interface calls in the timer routine and the packet
processor, but it does not change the problem.  

Its as if the execute-with-interface call is properly serialized but the
interface update recomputations occur afterwards in a manner that the
timer's execute-with-interface is able to disrupt it.  Interestingly
though, the packet processor does not cause the problem.

At the moment I'm stuck with 4.2, probably will move to 5.x this year...

Thanks,

Greg




Re: LW 4.2 on Linux, multiprocessing w/ capi

On Friday 22 May 2009 1:13:27 pm gregm32768@comcast.net wrote:

>

> I have a capi app that receives a stream of UDP packets, each of which

...

I'm not sure if I understood your problem correctly, but here's a thought:

Use mailboxes and allow the display updater to run "asynchronously" at whatever speed it needs to. The timer would simply send a blip to the mailbox, the updater would read the mailbox when it gets a chance. Here's an incomplete snippet of code from my current project that does this. The inner loop of updater-process ("dumping") dumps blips on the floor if the updater fell behind and doesn't wish to bother updating stale info - kind of like how Microsoft Word worked in the days of 8086's and 286's (you could type more quickly than it could refresh and text would appear on the screen in lumps).

pt

(defvar *updater* nil)

(defvar *updater-mbox* nil)

(defun start-updater ()

(unless +debug+

(setq *updater-mbox* (mp:make-mailbox))

(setq *updater* (mp:process-run-function "Updater"

(list :mailbox *updater-mbox*)

#'updater-process

*standard-output*))))

(defun kill-updater ()

(mp:process-kill *updater*))

(defun updater-process (stream)

(declare (ignorable stream))

(let ((mb (mp:process-mailbox mp:*current-process*)))

(loop

(let ((intf (mp:mailbox-read mb)))

(capi:execute-with-interface intf 'exec-regenerate intf)

(let ((intf (mp:mailbox-peek mb)))

(when intf

(loop until (mp:mailbox-empty-p mb)

do

;(format stream "dumping~%")

(mp:mailbox-read mb))

(capi:execute-with-interface intf 'exec-regenerate intf)))))))

Re: LW 4.2 on Linux, multiprocessing w/ capi


Many thanks- just after posting I thought of the mailbox approach- I
think I implemented something analagous to your code below.  What I did
was have the timer code do only a send to a mailbox, which another lisp
process was waiting on.  After waking up from the mailbox, the process
calls execute-with-interface for the stats update to the interface.  Bug
is now fixed.

It seems like the timer code runs in some kind of privileged condition
such that its able to bypass execute-with-interface protections or
somehow otherwise interfere with capi, whereas a regular process cannot.

CAPI is such an efficient way to put together a GUI.  My coworkers are
implementing a Python/GTK system and are spending weeks getting the
interface stuff to work right.  CAPI on top of CLOS is just crazy
powerful...

Regards,

Greg



Paul Tarvydas writes:
 > On Friday 22 May 2009 1:13:27 pm gregm32768@comcast.net wrote:
 > > 
 > > I have a capi app that receives a stream of UDP packets, each of which
 > ...
 > 
 > I'm not sure if I understood your problem correctly, but here's a thought:
 > 
 > Use mailboxes and allow the display updater to run "asynchronously"
 > at whatever speed it needs to.  The timer would simply send a blip to
 > the mailbox, the updater would read the mailbox when it gets a
 > chance.  Here's an incomplete snippet of code from my current project
 > that does this.  The inner loop of updater-process ("dumping") dumps
 > blips on the floor if the updater fell behind and doesn't wish to
 > bother updating stale info - kind of like how Microsoft Word worked
 > in the days of 8086's and 286's (you could type more quickly than it
 > could refresh and text would appear on the screen in lumps).
 > 
 > pt
 > 
 > 
 > (defvar *updater* nil)
 > (defvar *updater-mbox* nil)
 > 
 > (defun start-updater ()
 >   (unless +debug+
 >     (setq *updater-mbox* (mp:make-mailbox))
 >     (setq *updater* (mp:process-run-function "Updater"
 >                                              (list :mailbox *updater-mbox*)
 >                                              #'updater-process
 >                                              *standard-output*))))
 > (defun kill-updater ()
 >   (mp:process-kill *updater*))
 > 
 > (defun updater-process (stream)
 >   (declare (ignorable stream))
 >   (let ((mb (mp:process-mailbox mp:*current-process*)))
 >     (loop
 >      (let ((intf (mp:mailbox-read mb)))
 >        (capi:execute-with-interface intf 'exec-regenerate intf)
 >        (let ((intf (mp:mailbox-peek mb)))
 >          (when intf
 >            (loop until (mp:mailbox-empty-p mb)
 >                  do 
 >                  ;(format stream "dumping~%")
 >                  (mp:mailbox-read mb))
 >            (capi:execute-with-interface intf 'exec-regenerate intf)))))))


Updated at: 2020-12-10 08:41 UTC