I have no idea either, very weird. I also tested to simply pass (1 2 3 4) and using your updatePresentFeed function, however I put (traceAll) at the top of updatePresentFeeds, this is what I get:
task : -1000 (0 Pid NIL Cycles 0 Feeds Feeds (cond ((nand Pid (kill Pid 0)) (if (pop 'Feeds) (setq Pid (or (fork) (updatePresentFeed @)) Cycles 30) (task -1000))) ((=3D0 (dec 'Cycles)) (and (kill Pid) (off Pid))))) task =3D (-1000 0 (job '((Pid) (Cycles . 0) (Feeds 1 2 3 4)) (cond ((nand Pid (kill Pid 0)) (if (pop 'Feeds) (setq Pid (or (fork) (updatePresentFeed @)) Cycles 30) (task -1000))) ((=3D0 (dec 'Cycles)) (and (kill Pid) (off Pid)))))) I suspect that the above will not help much. Can you think of anything at all that might be interfering with the task execution, for instance running two servers/tasks listening on different ports at the same time in this very same parent? On Sat, Sep 4, 2010 at 5:26 PM, Alexander Burger <a...@software-lab.de> wrot= e: > Hi Henrik, > >> me. How exactly is (fork) working? The reference example: >> >> (unless (fork) (do 5 (println 'OK) (wait 1000)) (bye)) >> >> seems to imply that the current expression, ie. (unless ... ) is being >> rerun in the child (becoming the contents of *Fork) whilst execution >> continues to the (bye) in the parent. The (fork) call will return NIL >> in the child so the (do ... ) expression is being run there. It also >> seems to imply that the (bye) expression waits for the child to finish >> before shutting down? > > This description is not correct in some points. > > The PicoLisp 'fork' maps to the underlying fork() system call. When > fork() is called, an new process is created, and both processes (the > parent and the child) continue to execute from that point. At that > moment, both processes are identical, the only difference is that in the > parent process fork() returns the child's process ID, while in the child > 0 is returned. > > The PicoLisp (fork) function returns a number (the child's PID) in the > parent process, and NIL in the child process. So in the above example > > =A0 (unless (fork) > > is executed in the current process (which will be the "parent" > thereafter), and (fork) returns the PID of the child. This is non-NIL, > so the body of the 'unless' call is skipped by the parent, and it will > continue execution with the next expression (not shown here). > > In the child process, (fork) returns NIL, and the body of the 'unless' > call is executed. It consists of the two expressions > > =A0 (do 5 (println 'OK) (wait 1000)) > =A0 (bye) > > This is the code the child process sees. It prints five times 'OK' and > then exits (terminating the child process). > > Note that the (bye) is probably important, because otherwise the child > would continue with the next (not shown) expression which was already > executed by the parent 5 seconds before. > > Thus, (unless (fork) (do-something) (bye)) is a typical pattern to have > (do-something) done in a child process. In that regard, the formulation > "(unless ..) is being rerun in the child" is a bit misleading, as the > 'unless' is begins execution only in the parent, but after its condition > (the (fork)) is evaluated, we suddenly have two processes which execute > different branches in the code (the next statement in the parent, and > the body of 'unless' in the child). That's the reason for the name of > that system call, "fork". > > Then the formulation "(becoming the contents of *Fork)" is not correct. > The global variable '*Fork' is not changed in that process, it may be > set under program control _before_ the call to (fork) to contain > expressions which should be executed in all child processes. Perhaps you > meant '*Pid'? This is changed to a new value in the child process. > > Also, "whilst execution continues to the (bye) in the parent" is not > right, as the parent never sees the (bye). It is only there for the > child to terminate after it did its job. > > >> Anyway, having a wait call like that as is the case in my code could >> result in various race conditions, according to Alex he had to make >> (wait) "smart" in order to avoid common cases, I'm sure he can >> elaborate further on the details... In any case it works in my case > > Yes, though I would not say that there are race conditions. > > 'wait' is actually the PicoLisp "Event Handler". It can be called > explicitly, and is called implicitly by other functions (see the > reference of '*Run'). > > This event handler takes care of several things, listening on file > descriptors and watching timeout values. This includes all expressions > in '*Run' (typically installed and de-installed by 'task'), but also > internal events resulting from interprocess communication: The parent > relays 'tell' messages from a child to all other children, accepts > 'boss' commands (via 'hear'), detects when child processes terminate to > clean up their resources, and is needed to synchronize the database > between all child processes. > > So typically 'wait' processes a list of events. Now you may well call > another 'wait' in a task, and this in fact happens frequently during > database synchronization between child processes, or when GUI functions > execute. However, 'wait' must ensure that while processing a list of > events, a recursively called 'wait' does not re-execute the same event a > second time. For that, the inner 'wait' takes care not to look at the > events in the outer 'wait', and this may result that outer events will > never get executed if the inner 'wait' is run in a loop in some task. > > Anyway, this may get rather confusing, and isn't the way 'task's are > intended. I mean, instead that a task establishes its own timing loop > using nested 'wait's, one central capability of tasks _is_ being a > timer. That's why I recommended not to write such a loop in the task, > but execute the checking for that child process periodically with. > > >> but in order to avoid using (wait) Alex offered me the following >> version: >> >> (de updatePresentFeeds (Feeds) >> =A0 =A0(task -1000 0 >> =A0 =A0 =A0 Pid NIL >> =A0 =A0 =A0 Cycles 0 >> =A0 =A0 =A0 Feeds Feeds >> =A0 =A0 =A0 (cond >> =A0 =A0 =A0 =A0 =A0((nand Pid (kill Pid 0)) >> =A0 =A0 =A0 =A0 =A0 =A0 (if (pop 'Feeds) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(setq >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Pid (or (fork) (updatePresentFeed @)= ) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Cycles 30 ) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(task -1000) ) ) >> =A0 =A0 =A0 =A0 =A0((=3D0 (dec 'Cycles)) >> =A0 =A0 =A0 =A0 =A0 =A0 (and (kill Pid) (off Pid)) ) ) ) ) >> >> The main thing here is to initiate a task that is being run every >> second, when all feeds have been imported we terminate through the >> (task -1000) call. The first condition will be run initially (Pid is > > Correct. This will start a task which runs once a second, and has three > local variables Pid, Cycles and Feeds (a closure). > > >> The problem: It won't run at all, not even once and I have no idea >> why, it all looks good to me. > > Strange. I cannot see at the moment what might be the problem. > > > To test it locally, I tried the following, using a stub function for > 'updatePresentFeed': > > =A0 (de updatePresentFeed (F) > =A0 =A0 =A0(msg F '<feed> *Pid) > =A0 =A0 =A0(bye) ) > > =A0 (de updatePresentFeeds (Feeds) > =A0 =A0 =A0(task -1000 0 > =A0 =A0 =A0 =A0 Pid NIL > =A0 =A0 =A0 =A0 Cycles 0 > =A0 =A0 =A0 =A0 Feeds Feeds > =A0 =A0 =A0 =A0 (cond > =A0 =A0 =A0 =A0 =A0 =A0((nand Pid (kill Pid 0)) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 (if (pop 'Feeds) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(setq > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Pid (or (fork) (updatePresentFeed= @)) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Cycles 30 ) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(task -1000) ) ) > =A0 =A0 =A0 =A0 =A0 =A0((=3D0 (dec 'Cycles)) > =A0 =A0 =A0 =A0 =A0 =A0 =A0 (and (kill Pid) (off Pid)) ) ) ) ) > > =A0 (updatePresentFeeds (1 2 3 4)) > > This seems to work, printing the numbers 1 .. 4 (the "feeds") and the > PIDs of the individual child processes: > > =A0 1<feed>28662 > =A0 2<feed>28711 > =A0 3<feed>28763 > =A0 4<feed>28815 > > What exactly goes wrong? > > Cheers, > - Alex > -- > UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=3dunsubscribe > -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe