Re: Event design sketch
On Tue, May 11, 2004 at 02:06:51PM -0400, Dan Sugalski wrote: At 1:10 PM -0400 5/11/04, Uri Guttman wrote: i don't think there is a need for all those variants. why would alarm need any special opcode when it is just a timer with a delay of abs_time - NOW? let the coder handle that and lose the extra op codes. I didn't see any reason to not do absolute times as well as deltas. It's no big deal either way. You may need the distinction later. POE's mailing list has a thread with a periodicity of about six months: What happens when daylight-saving time comes or goes? The answer: All your short-term timers fire at once if the clock moves ahead, or everything stalls for an hour (or so) when it moves back. So far the best solution requires a distinction between absolute and relative timers: Adjust the relative timers to compensate for the shift, but leave the absolute ones alone. Relative timers tend to be used for things like timeouts and periodic polling. You don't want all your TCP connections to suddenly time out when the clock jumps ahead, and you don't want your log tailers to pause an hour when it skips back. However, you usually do want your absolute-timed jobs to run when the wall clock says they should be. Something to keep in mind. -- Rocco Caputo - http://poe.perl.org/
Re: use parrot;
On Sun, Oct 21, 2001 at 12:20:29PM -0400, Dan Sugalski wrote: I suppose. I hadn't planned on inlining parrot assembly into any other language. (The first person who suggests an asm() function *will* get smacked... :) You'll certainly be able to use modules written purely in parrot assembly. 1. B::Parrot 2. Parrot.xs 3. Providing opcodes for libperl functions and linking it in. I haven't suggested asm(), so technically I'm safe. Right? :) -- Rocco Caputo / [EMAIL PROTECTED] / poe.perl.org / poe.sourceforge.net
Re: Parrot multithreading?
On Thu, Sep 20, 2001 at 12:33:54PM -0700, Hong Zhang wrote: DS I'm also seriously considering throwing *all* PerlIO code into separate DS threads (one per file) as an aid to asynchrony. but that will be hard to support on systems without threads. i still have that internals async i/o idea floating in my numb skull. it is an api that would look async on all platforms and will use the kernel async file i/o if possible. it could be made thread specific easily as my idea was that the event system was also thread specific. I think we should have some thread abstraction layer instead of throwing PerlIO into threads. The thread abstraction layer can use either native thread package (blocking io), or implement user level thread package with either non-blocking io or async io. The internal io should be sync instead of async. async is normally slower than sync (most of unix don't have real async io), and thread is cheap. I agree. Threads, at least in spirit, provide a cleaner interface to threading and asynchronous I/O than user level callbacks. There's nothing stopping a compiler from generating event driven code out of procedural, perhaps even threaded code. Consider this: sub read_console { print while (); } sub read_log { print while (LOG); } Thread-new( \read_console ); Thread-new( \read_log ); sleep 1 while threads_active(); exit 0; A compiler can either generate threaded code that's pretty close to the original source, or it can generate asynchronous callbacks at the bytecode level. The same source code could compile and run on systems that support asynchronous I/O, threads, or both. Here's some parrot assembly that may or may not be legal at the moment. It shows what a compiler might do with the threaded source code on a system that only supported asynchronous I/O. read_console_entry: find_global P1, STDIN, main set I1, read_console_got_line jsr set_input_callback return read_console_got_line: # Assumes the AIO engine sets S1 with a read line. printS1 return read_log_entry: find_global P1, LOG, main set I1, read_log_got_line jsr set_input_callback return read_log_got_line: # Assumes the AIO engine sets S1 with a read line. printS1 return main: set I1, read_console_entry jsr thread_new set I1, read_log_entry jsr thread_new main_timer_loop: set I1, main_timer_done set I2, 1 jsr set_timer return main_timer_done: jsr threads_active ne I1, 0, main_timer_loop end __END__ -- Rocco Caputo / [EMAIL PROTECTED] / poe.eekeek.org / poe.sourceforge.net
Re: Parrot multithreading?
On Thu, Sep 20, 2001 at 04:13:48PM -0400, Michael L Maraist wrote: What we're going to do is fire up a new interpreter for each thread. (We may have a pool of prebuilt interpreters hanging around for this eventuality) Threading *is* essential at the parrot level, and there are even a few (as yet undocumented) opcodes to deal with them, and some stuff that's an integral part of the variable vtable code to deal with it. Whether it's considered ithread-like or not's up in the air--it'll probably look a lot like a mix. I'm also seriously considering throwing *all* PerlIO code into separate threads (one per file) as an aid to asynchrony. Just remember the cost in context-switching, plus the lack of scalability as the number of file-handles increases. Linux thread-context-switches are relatively brutal compared to say Solaris. Additionally you're consuming a new stack area for each file-handle. That's lots of overhead. One idea I haven't seen mentioned is have a fixed number of system threads to service a potentially larger pool of parrot interpreters. Essentially, physical threads become execution pipelines for the virtual machine. The limit on system threads can be tuned to optimally spread execution across available CPUs. It could be as small as 1 on single-processor systems that don't switch thread contexts well. -- Rocco Caputo / [EMAIL PROTECTED] / poe.perl.org / poe.sourceforge.net
Re: Calls for a Macro Assembler Guy
On Fri, Sep 14, 2001 at 11:20:36AM -0400, Dan Sugalski wrote: Okay, we've had a number of people in favor of a good macro assembler for Parrot. Given that, do we have anyone who'll volunteer to define, maintain, and extend the thing? (Presuming we jump off of the current assembler, which seems reasonable) There probably isn't a huge amount to do with the thing--maintain macro substitutions, handle local labels, manage sub definitions, and suchlike things. Anyone? j0. I'll do it. -- Rocco Caputo / [EMAIL PROTECTED] / poe.perl.org / poe.sourceforge.net
conveniences
The attached assemble.diff has assemble.pl look in its parent directory if the data files it needs aren't in the current one. This lets me camp out in t/ and assemble stuff over and over. The attached Makefile goes in the t/ directory. It lets me reassemble files by invoking make test.pbc. -- Rocco Caputo / [EMAIL PROTECTED] / poe.perl.org / poe.sourceforge.net --- assemble.pl-origFri Sep 14 11:20:05 2001 +++ assemble.pl Fri Sep 14 12:26:38 2001 @@ -59,7 +59,9 @@ # get opcodes from guts. -open GUTS, interp_guts.h; +open(GUTS, interp_guts.h) or + open(GUTS, ../interp_guts.h) or + die Can't get opcodes from guts, $!/$^E; my %opcodes; while (GUTS) { next unless /\tx\[(\d+)\] = ([a-z0-9_]+);/; @@ -68,7 +70,9 @@ close GUTS; # get opcodes and their arg lists -open OPCODES, opcode_table or die Can't get opcode table, $!/$^E; +open(OPCODES, opcode_table) or + open(OPCODES, ../opcode_table) or + die Can't get opcode table, $!/$^E; my $opcode_table; while (OPCODES) { $opcode_table .= $_; # $Id$ # Convenient makefile for assembling files. .SUFFIXES: .pbc .pasm .pasm.pbc: perl ../assemble.pl $ $@
macros
Attached is a patch to assemble.pl that adds very simple macros. I fear it's a bit of a hack, but I'm fighting my usual impulse to rewrite stuff. Attached is also macros.pasm, a simple usage case. It goes in t/ for want of a better place, but it's not a true test yet. -- Rocco Caputo / [EMAIL PROTECTED] / poe.perl.org / poe.sourceforge.net --- assemble.new-1 Fri Sep 14 12:26:38 2001 +++ assemble.pl Fri Sep 14 13:31:46 2001 @@ -93,24 +93,77 @@ my $listing=PARROT ASSEMBLY LISTING - .scalar(localtime).\n\n; - +# Macro stack. +sub MACRO_FILE () { 0 } +sub MACRO_LINE () { 1 } +sub MACRO_NAME () { 2 } +sub MACRO_ARGS () { 3 } +sub MACRO_BODY () { 4 } +my (@macro_stack, %macros, @input_buffer); # read source and assemble my $pc=0; my $op_pc=0; my ($bytecode,%label,%fixup,%constants,@constants); my $line=0; -while() { +while(1) { +my $sline; +if (@input_buffer) { +$_ = shift @input_buffer; +} +else { +$_ = ; +last unless defined $_; $line++; chomp; -my $sline=$_; +$sline=$_; s/^\s*//; s/\s*$//; +} + +# Comments and blank lines. if(/^\#/ || $_ eq ) { if($options{'listing'}) { $listing.=sprintf(%4d %08x %-44s %s\n, $line, $op_pc, '',$sline); } next; } + +# Macro definition. +if (m/^MACRO\s+(\S+)\s*(.*?)\s*$/) { + my ($label, $args) = ($1, $2); + my @args = split /, */, $args; + + die macro $label redefined at STDIN line $.\n +if exists $macros{$label}; + + $macros{$label} = +[ 'STDIN', # MACRO_FILE + $., # MACRO_LINE + $label, # MACRO_NAME + \@args, # MACRO_ARGS + [ ], # MACRO_BODY +]; + + push @macro_stack, $label; + next; +} + +# Macro done. +if (m/^MEND/) { + my $label = pop @macro_stack; + + # XXX: Verify that the macro uses all of its arguments at least once. + + next; +} + +# Within a macro. +if (@macro_stack) { + push @{$macros{$macro_stack[-1]}-[MACRO_BODY]}, $_; + next; +} + +# Opcodes with labels, or just labels by themselves. if(m/^((\S+):)?\s*(.+)?/) { my($label,$code)=($2,$3); if(defined($label) $label ne ) { @@ -173,7 +226,24 @@ last; } } -error(No opcode $opcode in $_) if(!$found_op); + +# Not an opcode. Is it a macro? +unless ($found_op) { + error(No opcode or macro $opcode in $_) unless exists +$macros{$opcode}; + error(Macro $opcode parameter count doesn't match definition) unless +@args == @{$macros{$opcode}-[MACRO_ARGS]}; + + # Expand the macro and push it on the input stream. + my @macro_body = @{$macros{$opcode}-[MACRO_BODY]}; + my @macro_args = @{$macros{$opcode}-[MACRO_ARGS]}; + foreach my $macro_line (@macro_body) { +for (my $arg_index = 0; $arg_index @args; $arg_index++) { + $macro_line =~ s/\b$macro_args[$arg_index]\b/$args[$arg_index]/g; +} + } + + push @input_buffer, @macro_body; + next; +} } if (@args != $opcodes{$opcode}{ARGS}) { error(Wrong arg count--got .scalar(@args). needed .$opcodes{$opcode}{ARGS}); @@ -219,6 +289,14 @@ } } $listing.=\n if($options{'listing'}); + +# Macro stuff. Make sure all the macros were closed. +my $bad_macros = 0; +foreach (@macro_stack) { + $bad_macros++; + warn macro $_ not closed (defined in $macros{$_}-[MACRO_FILE] at +$macros{$_}-[MACRO_LINE])\n; +} +die assembly stopped.\n if $bad_macros; my $output; # Todo : Local labels (begin with dollar sign) # Todo?: NAMESPACE (namespace name) # Todo?: SUB (sub name) # Todo : symbol IS string ; string # Todo : symbol IS 1234 ; integer # Todo : symbol IS 3.141 ; float # Todo : symbol IS ???; memory (variable) MACRO inc_and_print register inc register print register print \n MEND start: set I1, 0 set I2, 10 loop: inc_and_print I1 eq I1, I2, done, loop done: end
Re: Between-Opcode Callbacks
On Sat, Jul 07, 2001 at 05:51:00PM -0500, Jarkko Hietaniemi wrote: Not that innovative, really. :) Will basic blocks ever be different from scopes? The Book of the Red Dragon sayeth, p 528 in my copy: A basic block is a sequence of consecutive statements in which flow of control enters at the beginning and leaves at the end without halt or possibility of branching except at the end. [...] I suggested something similar in 1997: http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1997-02/msg00229.html The message proposed a tasking package that would dispatch atomic chunks of code. I eventually wrote one in Perl; it's on the CPAN as POE. In the Perl version, code atoms are just carefully coded subs. They would be basic blocks in a bytecode dispatcher. I still like the idea, so a few months ago I wrote a prototype of it in C for perl6-internals to tinker with. It's called phat, there is some discussion about it in the list archive, and the working prototype (for prototypical values of working) is still at http://poe.perl.org/phat/phat.c. -- Rocco Caputo / [EMAIL PROTECTED] / poe.perl.org / poe.sourceforge.net
ideas for signalling threads (was: Re: Does perl really need to use sigsetjmp?)
On Sun, 21 Jan 2001 17:28:49 -0500, Dan Sugalski wrote: The issue of 'which thread' comes in with signals. We can tell with real async events, since they'll have thread ownership tags on them if we care, but we can't do that with signals, and then we have the issue of "which thread" to deal with? Here's how I've dealt with signals in a cooperatively threaded Perl library. This design probably is too simple for Perl6, but it might be useful to consider. The library maintains threads' parent/child relationships. Each thread is something of a session leader for the threads beneath it, at least where signals are concerned. Signal events arriving at a thread are first propagated to its children, and this repeats recursively down to the leaf nodes on the family tree. In essence, signal delivery happens from the leaf threads back up to the ancestors they were originally destined for. Operating system signals are posted to the library's "kernel", which is the ultimate ancestor of every thread. This effectively (although perhaps not efficiently) broadcasts OS signals to every thread. The library's kernel decides which signals are fatal. It can do this because it's also the event dispatcher. Threads that don't handle fatal signals are stopped. Each thread has a destructor, so everything gets a chance to clean up, even after fatal signals. The library has an extra signal class: nonmaskable. Every thread that receives a nonmaskable signal is stopped regardless whether it handled the signal. Nonmaskable signals tend to be fictitious. They are generated by the library itself, and they're usually meant to signal a global shutdown. Two examples: UIDESTROY is broadcast when a GUI's main window is closed. The user wants this program to stop, and so it shall. ZOMBIE is broadcast when every thread has stopped running, and nothing is available to restart them. Imagine two threads playing ping-pong with an event. If one drops the ball, both threads' callbacks keep them alive. A program can detect when it has no more balls in play (the queued-event counter is 0) and shut itself down. (It's a little more involved than this: Watched filehandles are significant, for example, so there's a counter for those, too.) Here are two things Perl6 can do that my library doesn't, but I'm going to recommend against them in a moment. Perl6 will know which thread forked which process; it can track this information to send SIGCH?LD to appropriate threads. The system's SIGPIPE can be ignored altogether. Wherever a PerlIO function returns EPIPE, it can also post SIGPIPE to the same thread. I haven't implemented thess is my library because they preclude the ability to set global SIGCHLD or SIGPIPE handlers in some totally unrelated thread. Someone out there will want to do this, and it might just be me. It helps that these tend to be "survivable" signals; only the interested threads will ever notice them even when they're broadcast everywhere. Apropos of Perl 5: I've experimented long and hard on the language level in perl 5, and I have a test case for detect them without using handlers. It's unreliable though. That is, it may miss duplicate signals between checks. When is this an issue, though? -- Rocco Caputo / [EMAIL PROTECTED] / poe.perl.org / poe.sourceforge.net
callbacks, aio, threads and events (and a working C prototype)
Good morning. I've been thinking about defining atomic code units for a while, and I even posted something about it to p5p a few years back. The idea has matured since then, and I'd like to quickly outline it here: I've been defining code atoms using three rules: 1. Atoms begin at branch destinations. 2. Atoms end after each AIO-able opcode has set up a callback. 3. Atoms end after branches are taken. Before I continue on to explain how this ties into callbacks, AIO, threads, and events, I'd like to direct your attention to a C program I wrote. This program implements a tiny AIO subsystem (just timers), an opcode atom dispatcher, and a main loop. It suports at the opcode level the features needed for callbacks, AIO, threads and events at the language level. I submit for general consideration http://poe.perl.org/phat/phat.c. It may be compiled the usual way: gcc -Wall -o phat phat.c The rest of this message outlines what phat's design does or can be extended to do. Back to opcode atoms. Consider, for example, this little loop. phat runs ten of them, two each in five opcode interpreters. while (1) { sleep(5); print "something about the sleep call"; } After compiling and optimizing, the opcodes might look like this. label_1: sleep 5 label_2: print goto label_1 That's two atoms. The first ends after the sleep opcode has run, because it can be implemented in terms of AIO. The second ends after the goto has changed the interpreter's opcode pointer. While these atoms look like they end at statement boundaries, they can extend farther than that. The sleep opcode isn't allowed to block. Instead it asks the AIO subsystem to wait asynchronously, and it ends the atom. If the opcode interpreter has no pending events in its queue, it marks itself "blocked" before returning to the main dispatch loop. The main dispatch loop will ignore the interpreter as long as it's blocked. Part of the AIO timer request includes the address for label_2. This effects an ad-hoc callback at the opcode level. It asks AIO: "resume this interpreter at label_2 in five seconds". In five seconds, the AIO subsystem posts a wake-up event to the interpreter's queue, including the address of label_2. The act of enqueuing an event will reawaken an interpreter if it's currently marked as blocked. The main dispatch loop will then service the interpreter, and the atom will be executed. Callbacks? AIO? Threads? Each interpreter's queue holds events which tell it which atoms to run next. It's something of an atom execution pipeline. AIO and callbacks are just like what OP_SELECT does in phat, only they're exposed at the Perl level. Threads are implemented in as interleaved "run this atom" events in an interpreter's queue. Each event includes the address of the atom it will invoke. This simulates multiple instruction pointers, each taking its turn as the interpreter dispatches events to their appropriate atoms. Callbacks and threads coexist because they use the same underlying mechanism: the interpreter's execution queue. What about system threads? "Threads" within an interpreter aren't pre-emptive, but they do present a consistent notion of threading at the Perl level. That is, the Thread module would work even where system threads aren't present. System threads are still useful, though, and each interpreter can run in a separate one, where they're available. This allows two or more interpreters to run concurrently, whereas the "threads" in any given interpreter are still interleaved chunks of atomic code. With each interpreter running in its own thread, the main loop can focus on AIO. AIO events would still be posted to each interpreter's queue, but but the interpreters' sleep/wake cycles are handled by semaphores instead of timeslice calls from the main loop. In this way, threads prevent external libraries (for example, a DBD) from blocking entire programs. They would only block the interpreters they're running it; the other interpreters (and the main loop, and AIO) would be free to continue on. And language level events? Finally, if the per-interpreter event queues are exposed at the Perl level, they can be used for asynchronous inter-thread communication. Threads in one interpreter could post requests to a DBI module running in another. The client threads would be permitted to continue on, eventually receiving DBI responses as asynchronous callbacks. I think that's it. Thank you for reading. -- Rocco Caputo / [EMAIL PROTECTED] / poe.perl.org / poe.sourceforge.net
Re: Speaking of signals...
On Fri, 5 Jan 2001 16:47:25 -0500, Uri Guttman wrote: "DS" == Dan Sugalski [EMAIL PROTECTED] writes: DS I'm less worried about long running ops (whose fix is just a SMOP, DS after all... :) than I am blocked ops. We can be as clever as we DS want with event dispatch and async handling but it won't do us a DS darned bit of good if the interpreter's stuck waiting on a read DS from a filehandle or something. DS We can, I suppose, declare "No blocking system calls!" and let DS folks stuck with older OSes deal with it as best they can, but I'm DS not sure I like that a whole lot. yuck. if the perl level code makes a blocking call, that is their problem. if you want proper events and signals and async i/o you have to be prepared to handle callback delivery. by doing blocking calls you ruin that yourself. we can never fix bad programming at the perl level. i think inline callback delivery is a crutch but i think too many people seem to want it as they can't deal with event loops. and even i would want it for some simpler cases where i didn't want to make up events like with handling basic signal stuff. With a tightly integrated event loop, blocking perl level I/O can be implemented in terms of internal asynchronous I/O. An interpreter can then block while perl is free to do other things, like say run other interpreters. Consider a simple readline loop: while (FILE) { print; } Here's some hypothetical pseudocode. The opcodes assume a stack machine, but I'm sure something similar can be done with registers. label_1: read_line FILE branch_if_stack_0_is_undefined label_2 print_line goto label_1 The read_line opcode might be implemented as: If a line is available, push it on the stack and return. Arrange for the I/O subsystem to read a line asynchronously. When the subsystem receives a line, it will resume this interpreter context, putting the line on its stack. Pause the interpreter context, and return to the dispatch loop. The print_line opcode might be: Take a line from the stack, and give it to the I/O subsystem for writing. If the I/O system could flush it immediately (depending on autoflush and buffering), then return the number of characters written. Otherwise, the I/O system will resume this interpreter context, putting the character count on its stack, when the line finally could be flushed. Pause the interpreter context, and return to the dispatch loop. Pausing and resuming an interpreter is left as an exercise for the interpeter's subsystem. The pair, though, turn into a sort of bytecode level callback: call me back, branch to this label, or just resume after the "blocking" perl level call when the asynchronous task is done. "blocking" timers can also be implemented this way: sleep(5); ...; becomes: label_1: branch to label_2 in 5 seconds pause this interpreter label_2: ...; And finally, if interpreter contexts are subsumed into the notion of threads, then threads can be implemented in terms of them. Or they can be implemented in terms of system threads, where they're available and desirable. Consider: use IO::Socket; my $server = IO::Socket::INET-new( LocalPort = 2007, # echo + 2000 Type = SOCK_STREAM, Reuse = 1, Listen= 5, ); while (1) { my $client = gensym(); if ( accept( $client, SERVER ) ) { # async I/O inside Thread-new( \client_handler, $client ); # called in a new context } } sub client_handler { my $client = shift; while ($client) { # async I/O inside print $client $_; # async I/O inside } } This could very well be an event driven program, with all the tedious mucking about with callbacks done under the hood. Regardless, it could run the same as long as either threads OR async I/O are available. -- Rocco Caputo / [EMAIL PROTECTED] / poe.perl.org / poe.sourceforge.net
Re: Speaking of signals...
On Fri, 5 Jan 2001 23:46:33 -0500, Uri Guttman wrote: "RC" == Rocco Caputo [EMAIL PROTECTED] writes: RC With a tightly integrated event loop, blocking perl level I/O can be RC implemented in terms of internal asynchronous I/O. An interpreter can RC then block while perl is free to do other things, like say run other RC interpreters. doing this at the perl language level is easy since we control the stack and program counter. try doing it at the c level in the guts without munging the stack in ugly ways. by having the guts of perl always assume it is running in an event loop, we can get all these features without any ugly code. We seem to be in agreement, which is either really good, or really bad. :) Here's more detail into the implementation I have in mind. There is a set of opcodes-- mainly I/O and sleep-- that can be completed asynchronously if they block. The functions that implement these opcodes would never really block; instead, they would put interpreters to sleep and arrange for the AIO subsystem to wake them up when the operations complete. This simulates blocking in Perl programs without blocking perl's opcode dispatcher or the AIO subsystem's event loop. It does this in a way (always returning) that eliminates swapping C's stack (or Java's, or whatever's) and recursion. Furthermore, if Perl provides a way to spawn new interpreters (perhaps hidden within Thread), this gives people the opportunity to write event driven programs as if they were threaded. At first blush, the tiny TCP server at the end of [EMAIL PROTECTED] looks threaded, but it's really running under AIO. Or perhaps it uses real threads on systems where they're available, but it uses AIO where threads aren't viable. I have a prototype of something similar written in Perl; it uses 5005threads if they're available, but it will use AIO where they aren't. It also allows threaded runtime contexts and AIO-driven contexts to run together. Back to non-blocking opcodes. Consider reading a line, as if C $x = FILE; were called. Here's a hypothetical op_readline algorithm: 1. Try to read a line from the PerlIO subsystem. PerlIO returns immediately if it fails. 2. If a line could be read in step 1, push it on the interpreter's stack and return to the opcode dispatch loop. We're done. 3. Otherwise arrange for the PerlIO subsystem to read the line asynchronously. Have it call op_readline_complete when a line has been read, giving it these parameters: a pointer to this interpreter thread, and the results of the asynchronous readline. 4. Flag the interpreter thread as "blocked". This stops the Perl program in what appears to be a blocking readline() call, but the opcode/event dispatch loop can continue on. 5. Return to the opcode dispatch loop, which may decide to schedule opcodes in some other interpreter thread, or it may just sit idle if everything is blocked. Here's op_readline_complete, at least in theory: 1. It is called with a pointer to the interpreter that requested the asynchronous readline and the readline's result. 2. Push the readline result on the interpreter stack. 3. Flag the interpreter thread as "running" or "unblocked" once again. This looks as if the Perl program's FILE call has unblocked. 4. Return to the opcode dispatch loop. These are sample opcodes for a simple file grep function, with the corresponding Perl code in comments. 1: count_matches: # sub count_matches 2: pop $string # my ($filename, $string) = @_; 3: pop $filename 4: zero $found# my $found = 0; 5: push FILE # open FILE, "$filename"; 6: push "" 7: push $filename 8: strcat 9: op_open The interpreter can continue on to opcode 10 if op_open succeeds right away. Otherwise the interpreter is flagged as "blocked", and program control returns to perl's opcode dispatch loop. The interpreter resumes where it left off when op_open completes asynchronously. 10: label_1: 11: push FILE # while (FILE) { 12: op_readline op_readline was covered in detail above. 12: pop $_ 13: j_undef label_3 14: push$_ # $found++ if /\Q$string/; 15: op_match /\Q$string/ 16: j_undef label_1 17: inc $found 18: jump label_1 # } 19: label_3: 20: push FILE # close FILE; 21: op_close op_close may also pause and later resume the interpreter. 22: push$found # return $found; 23: return # } End. -- Rocco Caputo / [EMAIL PROTECTED] / poe.perl.org / poe.sourceforge.net
Re: Events and threads
On Sat, 06 Jan 2001 13:09:47 -0500, Dan Sugalski wrote: Okay, here's a big question that ties the two major pains we have in perl 6--how do we tie threads and events together? * Can all events be delivered to any thread? Yes, but in practice events probably would only be delivered to threads that were listening for them. Signal events are different beasts, though, although you could consider Clocal $SIG{INT} = \handler; as listening for an event. * Will events be delivered only to the thread that caused them? If so, what about threadless events? (Say, signals from the outside world) Not necessarily. Events can be a useful way to pass messages between threads. It might be fun to say: post( $thread, event_name = @args ); Signals are different. I've written in Perl an event driven thread dispatcher which has two different signal delivery modes. To its best of its ability, it dispatches SIGPIPE to the thread where it was generated. Everything else is propagated to every thread. Some signals, like SIGINT, are terminal. Threads that don't handle them are shut down. You can get situations where some threads shut down on SIGINT and others continue running, perhaps to save things. * Should events be filtered into multiple event queues? If so, how do we say which goes where? I've worked out some of this for a 5005threads-aware version of my dispatcher. The prototype I wrote uses one queue per thread. Events destined for a particular callback go to the thread where that callback lives. * Should async events see any state at all, or should they live in a Safe compartment (or something like it)? This wasn't an issue in my dispatcher. I had intended to go the route of a higher-level language written in terms of hidden asynchronous I/O (event driven threads). All language-level I/O would appear synchronous, except for signals, which are, again different beasts. Opinions? Now's the time when we must address this, so better weigh in with opinions before I choose... :) The thread-aware prototype is at http://poe.perl.org/poe2/. current-snapshot.tar.gz in that directory is a tarball of the whole tree. Design notes are in Readme, the notes directory, and source comments. -- Rocco Caputo / [EMAIL PROTECTED] / poe.perl.org / poe.sourceforge.net