How does receive work? I see that one of the arguments is a pattern for indicating what sort of message I am interested in, but I don't understand how to write/interpret such a pattern. Also, will I receive only the first message that matches this pattern? What happens if no messages match the pattern? Returns nil immediately? Block until such a message arrives?
Specifically, I would like to send a list as a message and recognize the message type based on the first element. Example (recognize that this starts with 'system): (list 'system 'link-request 'notify) I would like to receive the first message from the mailbox in *current-process* whose first element is 'system, returning immediately in the case where no such message is found. How could I set up a pattern-matcher for this? Can I use receive? Or will I need to use receive-with-timeout and a short time limit?
Better still, is there a way to set up a default handler that would perform predefined action whenever a message matching its pattern shows up? If so, I would like to use this. If not, I think it would be worth adding later. I can imagine writing an entire program made up entirely of default handlers for various message patterns.
I think that I'm very close to finishing process-linking, but my confusion over the messaging system is holding me back.
Eric
Eric Lavigne wrote:
How does receive work? I see that one of the arguments is a pattern for indicating what sort of message I am interested in, but I don't understand how to write/interpret such a pattern.
Depends on the matcher used. Erlisp currently only has COND and CASE based matcher, which are very lame. See test/matcher.lisp and test/messaging.lisp for examples.
It should be easy to write support for fare-matcher (or whatever matcher you want) though.
Also, will I receive only the first message that matches this pattern?
Yep. To process all matching messages you do RECEIVE with a 0 timeout in a loop, and make the timeout clause end the loop.
What happens if no messages match the pattern? Returns nil immediately? Block until such a message arrives?
Block until such a message arrives, or the timeout is reached (if one is specified).
Specifically, I would like to send a list as a message and recognize the message type based on the first element. Example (recognize that this starts with 'system): (list 'system 'link-request 'notify) I would like to receive the first message from the mailbox in *current-process* whose first element is 'system, returning immediately in the case where no such message is found. How could I set up a pattern-matcher for this? Can I use receive? Or will I need to use receive-with-timeout and a short time limit?
This should do the trick, though I can't test it before I get back to my laptop in a couple of hours:
(receive-with-matcher (cond-matcher m) ((and (consp m) (eq (car m) 'system)) ...) ((:timeout 0) nil))
Better still, is there a way to set up a default handler that would perform predefined action whenever a message matching its pattern shows up?
There is not. Could you define "whenever a message matching its pattern shows up" exactly? Would it be as if every RECEIVE has additional invisible clauses above the explicitly written ones?
If so, I would like to use this. If not, I think it would be worth adding later. I can imagine writing an entire program made up entirely of default handlers for various message patterns.
Doesn't seem very Erlangy to me, but that's not the purpose of Erlisp anyway. ;) If you can demonstrate to me why this would be an advantage and how we could implement it, then I'm all for it, but at the moment I can see neither.
- Dirk
I've written most of the code for process-linking, but I'm having some trouble with the function check-system-messages. When I compile it, I get lots of errors that I don't understand. When I run it, it continues indefinitely and slows my computer to a crawl.
A little explanation about the 'checking-system-messages in process: If a user program tries to do a receive, Erlisp should check for system messages first so the user program doesn't see them. There's a problem with receive calling check-system-messages and also having check-system-messages calling receive because it tends to create infinite loops. My solution was to explicitely check for this circularity, so receive will only call check-system-messages if it was not called by check-system-messages.
I have attached copies of the error messages and the modified source files (process.lisp and messaging.lisp). Hopefully someone has an idea what is going on. I will give this another try in the morning. Just one more day left for SoC, so I'm giving it one final push.
Eric
================== in process.lisp ================== (defun check-system-messages () (setf (slot-value (current-process) 'checking-system-messages) t) (do ((msg (receive-with-matcher (cond-matcher m) ((and (consp m) (eq (first m) 'system)) (rest m)) ((:timeout 0) nil)) (receive-with-matcher (cond-matcher m) ((and (consp m) (eq (first m) 'system)) (rest m)) ((:timeout 0) nil)))) ((not msg) 'done) (when (consp msg) (cond ((and (eq (first msg) 'link-kill) (not (slot-value (current-process) 'dying))) (error "Linked process died. My turn.")) ((and (eq (first msg) 'link-request)) (reverse-link (second msg) :link-type (third msg)))))) (setf (slot-value (current-process) 'checking-system-messages) nil))
Eric Lavigne wrote:
I've written most of the code for process-linking, but I'm having some trouble with the function check-system-messages. When I compile it, I get lots of errors that I don't understand.
Willem Broekema diagnosed the problem correctly I think. You're using a macro from messaging.lisp in process.lisp, but process.lisp is loaded /before/ messaging.lisp. (See erlisp.asd.) And currently it /has/ to be this way, because messaging.lisp depends on stuff from process.lisp to be loaded before it itself is loaded.
When I run it, it continues indefinitely and slows my computer to a crawl.
How can you run it if it doesn't compile?
Anyway, maybe you could put CHECK-SYSTEM-MESSAGES in messaging.lisp for the time being? I'll have a more thorough look at your code later...
- Dirk
When I run it, it continues indefinitely and slows my computer to a crawl.
How can you run it if it doesn't compile?
When I compile the rest of it and then paste that particular function into the REPL... I guess Willem's explanation shows why that worked.
Anyway, maybe you could put CHECK-SYSTEM-MESSAGES in messaging.lisp for the time being? I'll have a more thorough look at your code later...
Sounds like a good idea, but I will try to follow Faré's suggestion and create a separate process monitor. As Faré pointed out, my solution was too complicated. Hopefully I will have time to work this evening. For now I am busy with school.
Eric
Eric Lavigne wrote:
When I run it, it continues indefinitely and slows my computer to a crawl.
How can you run it if it doesn't compile?
When I compile the rest of it and then paste that particular function into the REPL... I guess Willem's explanation shows why that worked.
Ah right. Hmm, so then why the crawling? Is that because of the busy waiting style of the messaging system then? That really needs to be addressed any way... I think this should do the trick for AllegroCL, but I can't try it out just now:
(defun make-event () ... #+allegrocl (mp:make-gate nil) ...)
(defun event-wait (event mutex) ;note: this function should appear inside with-mutex block ... #+allegro (progn (mp:process-wait "wait for message" #'mp:gate-open-p event) (mp:close-gate event)) ...)
(defun event-notify (event) ... #+allegro (mp:open-gate event) ...)
- Dirk
I think this should do the trick for AllegroCL
i tested it out with allegro 7.0 trial. just need to unlock the mutex first in event-wait. otherwise works similar to openmcl.
i added it to my darcs repo. http://monday-monkey.com/repos/erlisp/
...bryan
(defun make-event () ... #+allegrocl (mp:make-gate nil) ...)
(defun event-wait (event mutex) ;note: this function should appear inside with-mutex block ... #+allegro (progn (mp:process-wait "wait for message" #'mp:gate-open-p event) (mp:close-gate event)) ...)
(defun event-notify (event) ... #+allegro (mp:open-gate event) ...)
bryan o'connor wrote:
I think this should do the trick for AllegroCL
i tested it out with allegro 7.0 trial. just need to unlock the mutex first in event-wait.
Yes, my bad...
otherwise works similar to openmcl.
i added it to my darcs repo. http://monday-monkey.com/repos/erlisp/
Cool. I'll integrate it in the main Erlisp repository tonight.
- Dirk
(defun make-event () ... #+allegrocl (mp:make-gate nil) ...)
(defun event-wait (event mutex) ;note: this function should appear inside with-mutex block ... #+allegro (progn (mp:process-wait "wait for message" #'mp:gate-open-p event) (mp:close-gate event)) ...)
(defun event-notify (event) ... #+allegro (mp:open-gate event) ...)
On 9/1/05, Eric Lavigne lavigne.eric@gmail.com wrote:
I've written most of the code for process-linking, but I'm having some trouble with the function check-system-messages. When I compile it, I get lots of errors that I don't understand.
Eric, it seems that "receive-with-matcher" is a macro, and it was not loaded at the time you tried to compile the code.
Therefore, the compiler thinks "r-w-m" is a regular function, and this form: ((and (consp m) (eq (first m) 'system)) (rest m)) is an argument for the function. Now, ((and ..) ..) is an invalid form as the car of the form must be the name of a function, macro or special form, but it is the list (and ..) instead. Therefore:
; ((AND # #) (REST M)) ; Error: Illegal function call.
and the other errors are similar.
- Willem
Dear Eric,
On 29/08/05, Eric Lavigne lavigne.eric@gmail.com wrote:
How does receive work? I see that one of the arguments is a pattern for indicating what sort of message I am interested in, but I don't understand how to write/interpret such a pattern. Also, will I receive only the first message that matches this pattern? What happens if no messages match the pattern? Returns nil immediately? Block until such a message arrives?
Erlisp should neatly decouple two things. (1) receiving, (2) matching.
Receiving is blocking, with an optional timeout. With a timeout of 0, it's non-blocking. What you receive is a list.
You can then match this list agains patterns -- matching is the natural way of expressing things in Erlang, but not so in Lisp. In Lisp, you *can* use pattern matching. I've written a pattern matcher (fare-matcher) with Erlang and ML in mind. Other matchers are available (there's one in UCW, IIRC, and then there's Screamer).
What should happen when you receive something that doesn't match any pattern? I don't remember what happens in Erlang: either the message is dropped or it raises an error, I suppose (gotta read the documentation). In Lisp, it could be configurable. See match vs ematch just like we have case vs ecase.
Better still, is there a way to set up a default handler that would perform predefined action whenever a message matching its pattern shows up?
The Erlang way of doing things would be to spawn another process for the things you want to be done in background of your main process. Remember: processes are cheap, in the Erlang model. Hopefully, so will they eventually be with Erlisp (especially processes sleeping on a receive).
[ François-René ÐVB Rideau | Reflection&Cybernethics | http://fare.tunes.org ] <hcf> information we gather and create overflows our means of managing it <hcf> our ppl r only happenstancely synergistic
Faré fahree@gmail.com writes:
What should happen when you receive something that doesn't match any pattern? I don't remember what happens in Erlang: either the message is dropped or it raises an error, I suppose (gotta read the documentation). In Lisp, it could be configurable. See match vs ematch just like we have case vs ecase.
unmatched messages are buffered. I've attached a small test module demonstrating this.
Goodbyte, Gerd.
-module(f). -export([r/0]).
l() -> receive {a,A} -> io:format('a: ~p~n', [A]) end, receive {b,B} -> io:format('b: ~p~n', [B]) end, receive R -> io:format('r: ~p~n', [R]) end, l().
r() -> Pid = spawn(fun l/0), Pid ! {b, bla}, Pid ! foo, Pid ! {a, blubb}.
Eshell V5.4.6 (abort with ^G) 1> c("/tmp/f", [{outdir, "/tmp/"}]). {ok,f} 2> f:r(). a: blubb {a,blubb}b: bla
r: foo 3>