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