Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Fetching contributors…
Cannot retrieve contributors at this time
1812 lines (1294 sloc) 61.7 KB
What This Is
This file is part roadmap and part wishlist. There's a third part
with stuff that's done, but you can ignore it unless you're morbidly
curious about the project's development history.
The roadmap section is relatively small and lists confirmed changes.
Most of these changes will break existing code, which is why they're
listed here. The changes which don't break programs usually don't
need to be documented this far ahead of time. :)
The larger wishlist section is composed of changes being considered
but which may never come to pass.
Everything is open to discussion, even the confirmed changes. If you
spot something you'd like to comment on, please feel free to mail me
directly. The POE mailing list might be a better place to discuss
changes since several people can discuss what you're commenting on.
Hopefully issues can be worked out before changes are implemented.
Typographical Conventions
Sections marked with "(!!!)" may break existing programs.
Various forms of "Xyz" are used throughout to mean "for every". For
example, "POE::Filter::Xyz" means "for every POE::Filter subclass".
Bits marked with question marks (like "????.??.??") are blanks to be
filled in once their values are determined. They are usually version
numbers and release dates. Almost everywhere, though, their context
gives some idea of the time frame involved. For example, an unknown
date 28 days after some release means that there is at least a month
to fix something after the release. If the release version is also
blank, then you're doubly safe, and so on.
Deprecations & Changes IN PROGRESS
These changes have begun or will begin shortly. If they plan to break
existing programs, there will be at least a month (usually two) of
advance warning.
XyzState to XyzEvent (!!!)
In the wheels, rename XyzState to XyzEvent everywhere. Wheels don't
define states, they emit events. Callivg Wheels' parameters XyzState
has been inconsistent and confusing. It's bitten a lot of people.
Call them what they are instead.
1. Release a version with XyzEvent and XyzState working side by side.
XyzState becomes undocumented in favor of XyzEvent.
Done: 2001-07-15.
2. Wait at least 28 days after the release before continuing this
schedule. Step 3 will be implemented on or after 2001-08-12.
3. Release a version that generates warnings when XyzState is used.
4. Wait at least 28 days after the warning release before continuing
this schedule. Step 5 will be implemented on or after 2001-09-09.
5. Release a version that does not support XyzState at all.
Deprecate queue_peek_alarms (!!!)
The new alarm functions let programs track their alarms by ID, so they
no longer need to peek into POE's alarm queue.
1. Release a version with queue_peek_alarms() deprecated and
Done: 2001-07-15.
2. Wait at least 28 days after the release before continuing this
schedule. Step 3 will be implemented on or after 2001-08-12.
3. Release a version with a deprecation warning in
4. Wait at least 28 days after the release before continuing this
schedule. Step 5 will be implemented on or after 2001-09-09.
5. Release a version with queue_peek_alarms() removed altogether.
Deprecations & Changes BEING CONSIDERED
These changes are not confirmed yet. They are still under heavy
consideration, and they may never actually happen. Even if they
include deprecation schedules, they are only tentative. I can't
overly stress that this is the wishlist section of the TODO file, but
I'll certainly try. :)
Several issues grouped together.
Fix Signal Event Dispatching (!!!)
Signal propagation (and the _signal event) are vestigial design from a
time when POE was to be the core for a multi-user object environment.
They provide some extra features that make writing MUDs easier, but
they hamper many general programming tasks that POE is now being used
Signal handling needs a basic redesign to make it more conducive to
generic programming, especially for components. The problem is that
handling a signal in one place does not prevent it from being
delivered elsewhere.
The example that brought this to my attention is an IRC client being
written with POE::Component::IRC. The main program traps SIGINT to
prevent the user from accidentally killing the client. Perhaps it
will ask the user to confirm the kill, to prevent errant keystrokes
from doing damage.
However, because SIGINT is delivered everywhere, POE::Component::IRC
dies regardless whether the main program catches that signal. This is
bad because the back-end IRC connection goes away when the user
interface doesn't necessarily want it to.
While the current signal propagation scheme is useful in some cases,
it's bad for the general case. Every component would need to agree
whether it should or shouldn't catch signals in a particular program.
That's madness.
2001-07-26 - Signals Getting Better?
Perl 5.7.2 or so has "safe" signals. Signals are handled in C, and
the main dispatch loop sets flags or something. The upshot is that a
really nasty hack I'd devised doesn't actually need to be implemented.
Furthermore, the other nasty hack (SIGINT polling) can go away once
everyone upgrades to the most bleeding edge perl release.
Hmm... that may not be immediately useful. Plan A goes on.
2001-07-26 - Tentative Release Schedule
1. Release a version with the new signal event dispatching semantics.
a. The three-phase signal dispatch and side effects.
b. $kernel->handle_signal() works.
For backward compatibility, signal handler return values are
significant unless $kernel->handle_signal() has been called.
Documentation changes:
a. Document the new signal handler dispatch phases.
b. Deprecate (but leave documented) the significance of signal
handler return values.
c. Document $kernel->handle_signal() and say it's recommended.
2. Wait at least 28 days after the release. The next stage of
breakage will fall on or after [to be determined].
3. Release a version that warns when signal handlers return true
without calling $kernel->handle_signal().
There will be a number of false positives on the warning,
unfortunately, but there's definitelay a work-around, and it lets
people know for sure that things are changing.
Docmentation changes:
a. Undocument the significance of signal handler return values.
4. Wait at least 28 days after the release. The next stage of
breakage will fall on or after [to be determined].
5. Release a version without warnings and without significant signal
handler return values.
2001-07-24 - Signal Propagation
In this design, signal dispatching happens in three passes.
In the first pass, a given signal is dispatched to the sessions which
registered handlers for it. The dispatch occurs in the order in which
handlers were registered, so older sessions get first crack at
handling signals.
In the second pass, every other session-- excluding the ones which
have received the signal already-- receive a generic _signal event.
Signal dispatch occurs from the root session (POE::Kernel) down
through children and grandchildren until finally the leaf sessions
(those without children) receive them.
The final pass deals with side effects of signals. If the signal was
fatal and no session handled it, then every session is stopped so that
the process can exit.
2001-07-24 - Signal Handling
Regardless how signals propagate, I do want to remove the significance
of signal handlers' return values. They are so easy to mess up,
especially with _default handlers, and it's trivial to create
processes that won't die without serious intervention.
Flagging signals as handled will require a new Kernel method, perhaps
$kernel->handle_signal(), which sets a flag that the dispatch function
(_dispatch_state) checks after the event handler (state) has returned.
handle_signal() could take a bitmask parameter to tell Kernel what to
do next with a signal. Here are some ideas for signal flags.
A no-op, but it lets programmers explicitly say that a signal
isn't handled, if they so desire.
Flag the signal as handled. By default, signals won't be handled
even if handle_signal() is called while they're being dispatched.
Tells Kernel to stop propagating the signal beyond this session.
I'm not sure if this is desired, though. Perhaps it stops the
dispatch at the end of the phase. For example, all the sessions
that request SIGHUP would still receive a SIGHUP event even if the
first one called SIGNAL_SQUELCH, but then the second dispatch pass
would be bypassed.
In the dispatch design #1, the side-effects pass will be executed
even if a signal is squelched. Squelching a signal just prevents
other sessions from seeing it.
Forces a signal to be treated as survivable.
Forces a signal to be treated as terminal in the final
side-effects dispatch pass. This makes otherwise benign (possibly
fictitious) signals suddenly lethal. Consider SIGBOGUS becoming
Still, though, if the signal is handled with SIGNAL_HANDLED
anywhere, it won't actually kill anything even if it's flagged
Flag the signal as terminal without any hope of handling it.
SIGZOMBIE is like that.
2001-08-08 - Ideas continue to gel.
I'll probably go ahead with the three-phase dispatch but leave the
return value alone. This shouldn't break much code, since signal
dispatch and propagation already tends to be broken. Most people who
deal with it seriously work around a whole host of problems.
The signal handler semantics will probably remain the same for now.
That's a big area of interface breakage, and it will cause problems
for people.
No... they both should change together. If they don't, people will
use more signal handlers once the dispatch is fixed. There will be
that much more breakage later when the public handler interface
SIGTSTP Does the Wrong Thing (???)
This change depends upon signal dispatching being fixed.
This one's marked with "(???)" because I'm not really sure it'll break
Gordon Matzigkeit writes 2001-02-16:
| If you haven't already, would you please add TSTP as a signal that
| should not be messed with in POE::Kernel:
| if (POE_USES_EVENT) { # include
| # If Event is available, register a signal watcher with it.
| # Don't register a SIGKILL handler, though, because Event
| # doesn't like that.
| if ($signal ne 'KILL' and $signal ne 'STOP'
| and $signal ne 'TSTP' # <-- HERE
| ) {
| Event->signal( signal => $signal,
| cb => \&_event_signal_handler_generic
| );
| }
I responded:
| I think a more correct implementation might set up TSTP and CONT
| handlers like in _APUE_'s program 10.22. That way, POE can
| gracefully suspend and resume itself while also propagating TSTP and
| CONT signals to sessions so they too can perform pause/resume tasks.
2001-07-26 - Update Schedule
A lot of people have been bitten by this. The TSTP handler might go
something like this:
1. Dispatch TSTP according to the current signal dispatch semantics.
2. If anything "handles" the signal, then don't stop the process.
3. If the signal remains unhandled, then stop the process. The code
to stop a process hasn't been designed yet, but here's the code
from program 10.22 so I don't have to keep looking in the book.
int main (void) {
int n;
char buf[BUFSIZE];
/* only catch SIGTSTP if we're running in a job-control shell */
if (signal(SIGTSTP, SIG_IGN) == SIG_DFL)
signal(SIGTSTP, sig_tstp);
/* ... code to do stuff ... */
static void sig_tstp(int signo) { /* signal handler for SIGTSTP */
sigset_t mask;
/* ... code to set up us the suspend ... */
/* unblock SIGTSTP, since it's blocked while we're handling it */
sigaddset(&mask, SIGTSTP);
sigprocmask(SIG_UNBLOCK, &mask, null);
signal(SIGTSTP, SIG_DFL); /* reset disposition to default */
kill(getpid(), SIGTSTP); /* and send the signal to ourself */
/* kill won't return until we receive SIGCONT or something */
signal(SIGTSTP, sig_tstp); /* reestablish signal handler */
/* ... code to set up us the resume ... */
4. The process stops in kill() and doesn't resume until kill()
returns. When kill() returns, dispatch CONT to everyone to let
them know they've awakened.
Several issues grouped together.
Stream Paradigms
I forsee the stream paradigm dictating how the API should be designed,
so it's a separate section. Otherwise I'd have to edit the API every
time something was changed here. At least as separate sections, they
can evolve separately until it's time to combine them.
2001-08-12: Torvald Riegel writes...
Detaching streams from their sessions is good.
However, I would prefer a real stream model. At the moment they
represent a source or destination including any processing needed
(filters, buffers, ...).
It might be better to think of streams as linked processors. Graphs
can be easily built (multicast, or parallel scanning, ...). There
would be interfaces that have to be supported by sessions or
objects. They are two roles: producer and consumer. data travels
through the graph, single pieces can communicate between each other
(flow control, ...).
Filter would be plain consumer/producer pieces, you could easily
include buffers and flow control, windows version could use threads to
have non-blocking IO on files, ...
Links (associations) between sessions would be needed (and for the
TODO version as well !). This kinda conflicts with the plans to not
include object layer features in core POE. But if we decide to go this
way, we should do it right and discuss more about it, right from the
start ...
2001-08-12: Rocco Caputo writes...
I'm inclined to use chained filters to do it. I'm against a complete
Session for every discipline on a stream because the $kernel->call()
between them will add a lot of overhead.
Perhaps consumers, producers, and links could be something different.
I'd like to see their interaction be as lightweight as possible.
I have the System V streams specification, and I have some notes about
how to pass messages between disciplines on a protocol stack. All my
previous design experiments have assumed protocol layers existed
together in some kind of local chain, not across several sessions.
2001-08-13: Torvald Riegel writes...
True. But they could be perl objects dealing with it, embedded in
sessions in any way. The idea behind that is that developers could
freely link these pieces and construct various data flow graphs.
Yes, they should be lightweigth. But as POE is heading to distributed
applications (at least I hope so :) the case where data comes from A
goes over B to C and all that on separate hosts gets more important.
Imaging being able to easily insert a monitoring component and stuff
like that. think about aspect/subject oriented programming, ... I
prefer a slow applications that takes less time to build than vice
versa :)
2001-08-14: Rocco Caputo writes...
I'm trying to avoid embedded objects in sessions. Wheels do this, and
it makes subclassing POE::Session very difficult. The problem arises
when a new kind of session changes its states' call signature.
Suddenly wheels, which have assumed POE::Session's call signature,
stop working.
In POE::IO::Stream, I'm proposing to move I/O management into a single
dedicated session. All the other sessions would use it in place of
wheels. The TODO file discusses it in detail.
Plug-in pieces and data flow graphs sound like a good idea. I'd still
like them to be as light as possible. Just because POE's useful for
distributed programming doesn't mean that's its only purpose. People
who write one-processor systems should not be penalized, if it's at
all possible.
Wheels Must Evolve
First, I'd like to say that wheels won't die entirely. For
compatibility's sake, they may become stubs (thunks?) into some other
kind of I/O abstraction. Certainly it will be more efficient to use
wheels' descendent(s), but at least old code won't die.
POE::IO::Stream is the abstraction's planned name. Suggestions are
welcome, and I'll document them here.
POE::IO::Stream might be just POE::Stream. It might also be
POE::Component::Stream, because it will be implemented as a component.
That is, Sessions creating streams will not actually own their
handles! This is funky, I admit, but it solves a few problems:
* Can't pass Wheel among sessions, because they set states in their
owners. Since the states won't be set anymore, it's possible to
pass streams around.
* Can't have multiple sessions watching for input on a single handle.
Since only POE::IO::Stream is really watching a given handle, that
rule isn't broken. However, it can be written to multiplex data to
every session with interest in a stream.
* Can't subclass sessions. Since wheels rely on sessions to have
predictable argument offsets, every subclassed session's states
require the same number and order of arguments. This already has
been a problem with Session vs. NFA.
* In the rare (but it happens often enough) case where a Session quits
before it removes its wheels, Kernel emits nasty warnings about
removing states from a nonexistent session. This won't happen
* POE::IO::Stream would need to monitor the comings and goings of
client sessions without them explicitly signalling it. Here's a
case for monitors that Philip Gwyn and others have wanted for a
while now. I can see the utility of such a thing.
* Probably others. I'll add them as I think of them.
The guts of various wheels would be moved into POE::IO::Stream
somewhere, and the wheels themselves would become a compatibility
interface between sessions and the new I/O system.
POE::IO::Stream will use Kernel's refcount_increment() and
refcount_decrement() methods to pass the handle "keep-alive" to
sessions waiting for data.
Stream constructor for file-like things:
$stream = POE::IO::Stream->open
... must be called with one of these:
Descriptor => DESCRIPTOR
Device => DEVICE
Resource => URI
... may also be called with these:
Driver => POE::Driver::Xyz->new()
Filter => ONE_FILTER
Stream constructor for socket listeners:
$stream = POE::IO::Stream->listen
FromAddress => BIND_ADDRESS
FromPort => BIND_PORT
... see the notes for Handle in the connect() constructor notes.
... see the notes on From and To for the connect() constructor.
Stream constructor for socket connectors:
$stream = POE::IO::Stream->connect
FromAddress => BIND_ADDRESS
FromPort => BIND_PORT
... to remain similar with the listen constructor, a Handle parameter
can be added instead of Domain, Type, and Protocol. Further,
FromAddress and FromPort can be omitted (they're optional anyway).
... people have requested ways to bind to multiple addresses and
ports. Perhaps instead of FromAddress and FromPort, another parameter
can be added:
From => [ 'ADDRESS:PORT', 'ADDRESS:PORT', ... ]
... likewise, ToAddress and ToPort could be specified:
... would multicast be done as arrayrefs for To?
Stream constructor for connectionless sockets:
$stream = POE::IO::Stream->peer
FromAddress => BIND_ADDRESS
FromPort => BIND_PORT
(ToAddress? ToPort?)
... see the notes on From and To for the connect() constructor.
... see the notes for Handle in the connect() constructor.
Each variation of a stream might be its own class. I'm not sure about
that yet, since it fragments the design and makes finding bits of code
harder than usual. What is the benefit again?
Events that can be emitted. These are parameters for the event_xyz()
and constructor methods:
(not really)
These are common methods for most/all of the differently constructed
resume RWX_FLAGS
... maybe more.
Wheel::ReadWrite Needs Input Flow Control
This change can go ahead now that filter changing has been fixed.
Rewrote this section. After lots of thought, note-taking, some
experimentation, and copious discussion with Torvald Riegel on the
subject, I've decided on two kinds of input throttling. Neither kind
uses input buffers, which probably will upset Torvald. He strongly
believes in input buffering within ReadWrite, and I strongly disagree
with him. We've been disagreeing on the subject for months.
The first form of flow control uses Torvald's proposed pause_input()
and resume_input() methods for ReadWrite. In prototypes, they have
successfully been driven by high- and low-water events from other
wheels. That is, when the "write" wheel's output buffer fills up, it
pauses input on the "read" wheel. The prototype is symmetric; each
wheel throttles the other. I think it can be expanded into a useful
stand-alone component for piping data between two handles. It would
simplify the proxy sample.
The second form of flow control is flawed, and I need to work on it
some more before including it here.
2001-07-26 - Related Issues
This won't ever get off the ground until POE::Filter::Xyz are
de-optimized. Bleah! But it's the right thing to do after all these
2001-07-26 - Update Schedule
1. Release a version with POE::Wheel methods pause_input() and
resume_input() from Torvald's patch.
Document the new methods, and add tests for them.
Do the other thing, which isn't fully designed yet.
2. Release it!
2001-08-08 - Status
Filter::Xyz are deoptimized, I think. I need to expand test 19 to try
changing filters rapidly before I close that. Test 19 hurts my brain.
2001-08-12 - Status
Test 19 got enhanced with several new tests. Rapid-fire filter
changing works now, so input flow control is cleared for take-off. :)
Instant Write (???)
The earliest documentation I have on this issue is March 2000, so this
is back-dated to then.
Artur has, for a long time, wished that $wheel->put() immediately
tried to write data to the socket, rather than buffer data and write
it as a result of select_write().
He claims it saves about 1/3 of the state calls in the wheels.perl
sample program. I'm inclined to believe him, but it also complicates
wheels' design somewhat.
On the other hand, people tend to think that calling $wheel->put()
should put stuff right away. Maybe "least surprise" is enough to
warrant the change.
Make Things Inheritance-Friendly
There was a time in POE's development where just using @ISA would make
method calls three times slower. Whatever perl was doing got fixed,
and now it's safe to use inheritance again.
b01_solo: 13 wallclock secs ( ... ) @ 924187.73/s (n=10000000)
b02_parent: 12 wallclock secs ( ... ) @ 901408.45/s (n=10000000)
b03_child: 12 wallclock secs ( ... ) @ 919540.23/s (n=10000000)
Session should be made inheritable, if it's not already. The base
Wheel, Filter, and Driver classes maybe. Component could provide some
useful common things; perhaps Philip Gwyn can add interoperability
stuff there and make components do the right things.
Kernel? Should it be inheritable?
2001-07-25 - Status
Removed const and enum from Session and NFA, turning them into plain
constant subs instead. This makes the constants inheritable.
Something must be done about the macros, though. I may have to back
them out into method calls, which WILL be slower than inlined code.
2001-08-08 - Status
Requires wheels not to be so closely tied to sessions. Especially
requires them not to insert states into sessions, since different
kinds of sessions may have different parameter orders or counts. See
POE::IO::Stream somewhere else in this document.
Miscellaneous issues without proper homes.
Chris Fedde <> is working on a project that uses
Net::LDAP and POE. He may have integrated the two.
IBM's Bisync protocol, invented sometime around 1966, is a layered
ASCII protocol using many of the control characters which have since
fallen into obscurity and disuse. It's a useful way to encapsulate
streams, and I think there should be a filter for it.
It's also very simple. Google for "bisync soh stx etx" and "bsc soh
stx etx" reveals a lot of stuff, including these links:
There are error detection and correction layers over the basic frame
format, but they don't need to be implemented right away.
Julian Morrison <> has been working on a
subset of it, Filter::SyncStream, which implements variable- length
blocks with synchronization characters. It's like Filter::Block, but
it can recover if a block becomes corrupt. Filter::Block assumes a
reliable transport such as TCP, so Filter::SyncStream may be better
over unreliable channels like raw serial lines or UDP or something.
Asynchronous DBI
This is a wishlist item. A lot of people would like to run async DBI
calls, even the DBI people. Check the DBI mailing list archives (?)
for discussion on it. It's rumored that someone is working on it from
the DBI end.
MJD's Async module manages a pool of child processes. It may be able
to handle this, although a lot of DBI discussions have concluded that
database libraries aren't very fork safe.
Andrew Chen <> is interested in asynchronous
DBI as well.
David Esposito <> has said he plans to try some
asynchronous DBI ideas sometime.
Rob Bloodgood <> posted some interesting work-arounds:
Truthfully, it REALLY depends on your query.
I wrote a multiplexer on my fetch() loop, so I can read updated/new
data and still serve requests. THAT part was actually pretty easy,
and fetching rows is quite fast.
But the query itself was a %#!$@%. So, long days of optimization
which led to the following solution:
Since certain parts of my data view took forever
but I only needed them at a 1-day granularity
I made views out of those slow parts
and then run a daily procedure that updates that SLOW part into a
so that when my query runs
and mentions THAT data (that table)
it takes <.1 second on that part
instead of >30 seconds.
Depending on UR db, you can get a rundown on what parts are the slow
parts... Oracle has its EXPLAIN PLAN, dunno about others but I would
be surprised if similar wasn't available for, say, MS SQL, MySQL,
Artur suggested waiting for thread support. I think he wasn't
entirely serious at the time, but he's deadly serious these days. :)
It may be possible to grab a socket handle from the DBI library and
select_xyz() on that. I have no idea how the details would work, but
I'm pretty sure each database connection could still only field one
request. Bleah.
Deprecate Filters' get() Methods (!!!)
Now that get_one() and get_one_start() are implemented, should the
older get() methods be deprecated? I'm not sure, but I wanted to
document it here.
Both sets of methods certainly do duplicate code. At the very least,
they should be normalized and/or combined so the code is easier to
Simplify Session Definition
This change requries that sessions be made inheritance friendly.
Add new base classes: POE::Session::Inline, POE::Session::Object, and
POE::Session::Package. Each somehow scours their subclasses'
namespaces for methods or functions that begin with "poe_". The base
classes provide a poe_spawn() method that uses the "poe_" symbols to
build and instantiate inline, object, and package sessions
This would vastly simplify session definitions, for many simple cases.
package ThingySession;
@ThingySession::ISA = qw( POE::Session::Object );
sub poe__start { # two underscores
sub poe__stop { # two underscores
sub poe_event {
sub private_method {
Programs would call ThingySession->spawn() to create a new object
session with the "poe_" methods as event handlers.
I think Artur Bergman mentioned this to me once, but I was too busy to
think about it. It's a rocking idea, though.
POE One-Liners are HARD
It's a shame that you can't write many one-liners in POE. What can be
done about this?
My first inclination is to develop something SO high level that it
does what you mean. My second inclination is to hit myself in the
head until I stop thinking about it. :)
The POE Community Wants a Bigger Hand in Development
The YAPC 2001 POE BOF agreed that its members want a bigger part in
the project's development. This is great! It should reduce my
workload and generally expand POE knowledge across a larger group of
people. If I get hit by a passing blimp, life goes on without me.
For such a group to remain organized, however, I feel the need to
codify the goals and heuristics that guide my own development.
Certainly these would just be guidelines. Evolution happens, and they
may change over time as the project continues to grow up, but it's a
good idea to know going into it what's expected to come out of it.
So, what am I trying to do here? What are the decision priorities
when making trade-offs? Where do I want to go today?
2001-07-26 - Still Not Done
I'm finding this a lot easier to say than to do.
2001-08-14 - Still Not Done
I think I need to just dive into this one. Give one or two people
development access and then hit them with sticks if they break stuff.
My biggest worry, I think, is that people won't give adequate
forethought before adding new code to things. Of course "adequate"
for me is probably "way too much" for most other people. This file is
evidence of that.
Perhaps some sort of groupware system where we can talk about stuff.
Ideally, I suppose it would be the TODO file with multiple authors.
There are some options here:
Blech. Simple tasks turn into multi-page processes of doom.
Slow, tedious, flaky, and ugly. About all it has going for it is
a lot of users, which says something, but I'm not sure what.
Make the TODO file group-editable. Again, this could be through
SourceForge. On the plus side, people won't need to go through
the web interface to make changes. This may become the best
option, actually.
Group-edited web site. I don't know much about this one.
My groupware outline, never completed. It is a self-contained POE
web server/database. Artur would like to finish POE::Component::
Server::HTTP, and I'd rather use that than reinvent it for my own
Mailing List
Guts talk on the main list? I know Torvald is using the list that
way, reading from here and posting there. I get the impression,
though, that it would be easier and more direct if he could add
his comments directly to this file instead of waiting for me to.
This news server mirrors and archives all the mailing
lists. It provides a persistent record of conversations, and
sufficiently advanced newsreaders will present it threaded. This
might work well for some people, but there's still no way to
summarize contributions into a coherent design. Maybe an offshoot
of YASD is in order. I'll work on a database design that models
my interpretation of the ideal development model.
Are there any other free, usable groupware things?
Give Exported Constants Some Prefix(es)
This change depends on sessions becoming inheritance friendly. I'd
like to put the prefix thing into a base class so everyone can enjoy
<Micksa> eep, poe uses yet another calling convention
<Micksa> like:
<Micksa> my ($kernel, $heap, $session) = @_[KERNEL, HEAP, SESSION];
<Fletch> that's the normal convention, it just doesn't hardcode what
order particular arguments will be passed
<Micksa> it's, like, the 4th way I've seen so far for passing named
<Fletch> it's so that if calling order ever changes programs that use
the symbolic constants don't break
<Fletch> it's really no different than say
`my($kernel,$heap)=@_[0,3]', just that the 0 and 3 come from
constant subs rather than magic numbers
<Micksa> problem is, the symbolic constants are rather likely to
<Fletch> maybe there could be an option to prefix them, like
<Micksa> *shrug*
That sounds like a good idea.
2001-07-25 - Development
use POE::Session qw( ConstPrefix => 'POE_SESSION_' );
It would also be fun to tweak TRACE_ and ASSERT_ through POE::Kernel's
and POE::Session's import() methods.
use POE::Session qw( Traces => [ DEFAULT => 1, GARBAGE => 0 ] ) ... or
2001-07-26 - More ideas
use POE::Tweak qw( Trace => qw( +default -garbage ),
Assert => qw( +default -reference ),
Tweaks would be global.
2001-08-08 - Development
The previous idea is still too verbose. Here's something easier that
Artur came up with. Artur would like to see a POE::strict directive
that turns on everything. It's certainly more convenient than the
other goop. So:
use POE::strict qw( events states parameters returns );
use POE::assert qw( default -references );
use POE::trace qw( garbage references );
These would still need to be before the first instance of C<use POE;>
because they dis/enable things at compile time.
2001-08-14 - Module Tweaks
Modules should be allowed to access global tweak flags at C<use> time.
The tweaks library should make this easy.
Artur wants lexical stricture. Gads, that would make things slow!
Right now stricture is implemented at compile time, by enabling code
that's normally not compiled into the program. Requiring runtime
tests for everything would add a big (?) chunk of overhead.
Known interested people: Artur, Rocco :)
Artur is working tirelessly on iThreads (now C<use threads;> in 5.8.0
or something). He's even got a patch to POE::Kernel with adds them.
I need a day's worth of tuits to try this out.
Threads would really enhance IKC.
Known interested people: Artur, YAPC::EU
POE needs a thorough code review. It needs to stay still long enough
to be examined. :)
Known interested people: Artur, YAPC::EU
Inter-Kernel Communication
Artur says there's a need for an official IKC. I'd rather let
Philip's become it than try to write my own. I guess maybe what
Artur's asking for is tighter integration between POE and IKC.
To do: Find out what Artur means. :)
Known interested people: Artur, YAPC::EU
Automatic Postbacks
Torvald Riegel writes:
What do you think about some sort of automatic postbacks? A third
type of generating an event, which would be posted to the target
session. The associated state's return value would be returned to a
postback that is specified when sending the first event. So one
would use something like $kernel->postandreply($target, $event,
$self->postback(...), @args)...
Advantages would be that the target session would not need to care
about handling postbacks and returning values through them. One
more function would have to be maintained and postacks would need to
be kept somewhere at the event's structures. Garbage collection
shouldn't be a problem since the postback would be a normal
parameter otherwise.
Really good would be if this return-postback could be set as another
state's return-postback. So if user() would postandreply server()
but server() would have to call worker(), the postback could be
handed over to worker() and it would reply through the postback.
This would only be a variation of postandreply, I think.
I know everything could be done using postbacks given as state
arguments, but the above would make returning values simple and
easier to read at the server() side.
Others have requested it too.
Even Simpler POE::Component::Server::TCP
Artur would like PoCo::Server::TCP to be simpler. In fact, he'd like
it to be so simple that it wraps accepted sessions as well, possibly
not spawning new sessions at all.
The idea would be to provide Reader, Writer, and/or Error handlers
instead of Acceptor. The server component would do its accept thing
and create a generic session (possibly not) that does generic reading
and writing. The handlers would customize things from there.
Artur has some specific ideas how this should work.
2001-08-08 - Status
I haven't seen Artur's specifications, but embedding the ReadWrite
into the server component would let Fletch write Server::SSL as a
drop-in replacement for Server::TCP. That's fun.
Change Internal Helpers To Static Functions
This change may never happen if it hinders the ability to inherit
Despite recent optimizations in perl 5, object methods are still a wee
bit slower than function calls. Furthermore, those changes aren't in
older versions of perl where POE still runs fine.
Because of Kernel restructuring in 0.05_02 (1999.01.12) prohibiting
multiple Kernel instances, we can finally make POE::Kernel's private
methods static functions.
What do we get? Better performance (by a factor of 3 or so) in older
versions of perl. Less argument passing internally (no $self; the
lexical $poe_kernel instead). Greater encapsulation, but who cares
about that?
This is a relatively easy change, and it would make a good starter
project for someone who wants to get familiar with and
2001-07-29 - Chances Decreasing
The more I think about this one, the less I like doing it. At some
point, things should be subclassable.
Batch Remove Resources
Peter J. Braam would like a way to flush all pending events for a
session. This would be FIFO events, since there would already be a
method for alarms.
Kirill would like a way to batch-remove all selects when it's time for
a session to shut down.
+ alarm_remove_all() is done
To do:
* Add select_remove_all()
Wheels confound the ability to remove all selects.
* Add event_remove_all()
Other resources which keep a session alive: extra reference counts,
and aliases. Should there be batch remove functions for these as
I'm starting to worry about the side effects of stopping sessions
willy-nilly. Is there a good example of stopping a session while it's
busy processing events? "Good" means the session won't corrupt
anything by not handling whatever is in its queue.
What of everything_remove_all() ?
POE::Kernel's yield() is Nearly Universally Hated (!!!)
Especially by people who know threads. It implies blocking in one
session and resumption in some other, and it freaks people out when it
returns immediately.
These names have been suggested instead:
post_self (2 votes)
post_me (1 vote)
post_myself (1 vote)
postal :) (0 votes)
enqueue (1 vote)
postpend (1 vote)
continuation (1 vote)
continue (0 votes)
$session->post (2 votes)
This is a pretty basic function, and it's one a lot of people are
probably using. This deprecation should have a longer than usual
schedule, to avoid unnecessary breakage.
The $session->post() idea is doable, but not until Session and NFA can
be subclassed. There's another section in this TODO file about
subclassable sessions.
POE::Kernel's call() Pretty Much Sucks, Too (!!!)
The call() method is incongruous, and that's putting it nicely. It
should be deprecated for inter-session calls, and it should probably
become $session->call to match $session->post, or something.
General ideas:
Eliminate the ability to call() outside the current session.
Possibly move the call() method to POE::Session. $session->call() ?
ARG0..ARG9 May Go (!!!)
HEAP, KERNEL, SESSION, and the other event handler parameter constants
were introduced to eliminate a dependence on their positions in @_.
However, the ARG0..ARG9 parameters aren't descriptive and still
contain position dependence. This robs event parameters of many of
the benefits of using symbolic constants in the first place.
This is the current plan to deprecate them:
* Introduce new constants for the different built-in events. Leave
ARG0..ARG9 for user parameters.
* Document the new constants instead of ARG0..ARG9.
* Document that parameters may move around in the future, so their
positions in ARG0..ARG9 will not be guaranteed.
* Release version ?.??.
* Wait at least 28 days after releasing the documentation change
(until ????.??.??) before continuing this deprecation schedule, to
give people time to react to the initial round of changes.
* Generate warnings when ARG0..ARG9 are used for built-in events.
This will require some logic within those subs, removing their
constant nature and slowing things down in general.
* Release version ?.??, and announce that the ARG0..ARG9 built-in
parameter deprecation is proceding apace.
* Wait at least 28 days after releasing the warnings (until
????.??.??) before continuing this deprecation schedule, to give
people time to react to the warnings and adapt their code to the new
symbolic constants.
* Remove the warnings from ARG0..ARG9, making them constants again and
speeding things up once more.
* Release version ?.??, and announce that the ARG0..ARG9 built-in
parameter deprecation has completed.
Finish POE::Message
POE::Message would be a high-level inter-session message object,
trading away some speed for a lot of useful features:
It can encapsulate named parameters instead of the vaguely icky
It can encapsulate several postbacks, including refcounts which keep
the sender alive.
It can encapsulate inter-Kernel routing, messaging, and directory
It can encapsulate automatic postbacks and exceptions.
I have a prototype which must be developed further before entering the
Automatic Parameter Exports
Turn @_[KERNEL, HEAP, etc.] into regular variables, somehow. A lot of
people would like this, and the original object layer had code to do
this. Of course it cheated: all code was kept in a database and had
to be eval'd into existence, so it could do what it liked to your
programs. But still, that was a good idea, it still is, and someone
should do something about it.
Spin Off Useful Technologies
POE only really needs a few modules. The rest are options which may
not always be needed, or they're stand-alone modules that someone else
may find useful. For example, POE::Filter::*; POE::Preprocessor; and
POE::Pipe::* are useful by themselves. Wheels are pretty useful, but
they're not always necessary. It may be both useful and convenient to
split POE into smaller distributions and present one or more Bundles
to selectively load just the parts that are needed.
This is the current plan to spin off useful modules from POE:
* Develop a real plan for this. Most of this is tentative.
* Organize subsets of POE into useful bundles, and document them.
Make Bundle::POE the default.
* Split out wheels?
* Split out the Preprocessor? Should it remain a POE::* module?
* Split out filters? They're useful by themselves; should they remain
POE::* modules?
* The samples are huge and obscure. Split them into a separate
distribution which doesn't install itself.
* Most of the documentation is theory and usage, and it doesn't really
fit in manpages for modules themselves. Split it into separate POD
files, and maybe split them into Bundle::POE::Docs.
Make Driver::SysRW the Default for Wheels
This is a quick, inexpensive change. Driver::SysRW is the only driver
to be developed/used over the course of like three years. Make it a
default so people can stop typing it.
This should be an easy fix, but it involves tweaking several wheels.
It might be a nice introduction to wheels for someone who wants to
know more about them.
Make Filter::Line the Default for Wheels
This is an inexpensive change, but it has dubious value. Think about
it some more first.
This should be an easy fix, but it involves tweaking several wheels.
It might be a nice introduction to wheels for someone who wants to
know more about them.
Split Dual-Mode Functions into xyz_set and xyz_clear
This would make the functions' purposes more clear and eliminate some
branches that are currently tested all the time. The existing
dual-mode functions could remain as thunks for the single-purpose
The "June 2001" alarms functions already do this. What about
select_xyz and the others?
Evaluate Torvald Riegel's Synchronous NFA Design (???)
Torvald wants POE::NFA to run entirely synchronously like a proper
nondeterministic finite state machine ought to. I'm against that
because I haven't seen a proper need for it and it puts what I see as
an artificial limit on the class.
To do:
* Distill Torvald's e-mail on the subject and include a summary here.
* Determine whether his design can be implemented in a way that
doesn't limit NFA to a strictly correct NFA design. Asynchronous
NFA events are useful and should also be supported.
This is an extra feature.
POE::Semaphore encapsulates a semaphore-like thing. Instead of
blocking and releasing when the semaphore reaches zero, though, it
fires an event.
Tied scalar.
raise() and lower() methods.
Constructor takes details of the event to fire. Possibly acts as a
postback or creates one internally.
Artur's hooks, plus Philip's work on this. How can it be incorporated
into Kernel and/or a base Session without big maintainability and/or
performance penalties?
Session Relationships
POE::Relationship::Channel or something - A subscribe/broadcast model,
useful for inter-session communication channels and monitors. Philip
Gwyn has wanted monitors for a long time. CanyonMan wants something
similar for inter-session coordination.
POE::Relationship::Matrix - An XY or XYZ grid of sessions with
neighbors. Methods to add and remove sessions. Methods to broadcast
events to neighbors based on radius or some other distance.
POE::Relationship::Network - A directed graph of sessions, suitable
for writing neural or other networks. Convenience methods for
broadcasting events to connected sessions.
2001-08-13: Torvald Riegel writes...
I'd like to note that these are patterns which should be layered on a
real link. These relationships (relations would be better) are called
associations between objects (at least in UML and what I've seen so
far). The ends of such associations have a given multiplicity and
role(name)s. These roles identify interfaces on these ends. So
interface definitions for sessions or objects (lets call them objects
since they have the same properties...) should be used as well.
But this is the object layer, actually. I wouldn't mind if it would
be used widely (when one exists), but the last decision I heard from
Rocco was that it shouldn't be included but strictly layered on top.
However I do think that it would make sense for POE basics as well.
I do want to include associations for POE::Script, which will exist
soon. (the plans for it are done, I just need some more time,
implementation won't be so hard). A well designed object layer would
be better, but maybe we can use the script thing as a testcase and to
make writing POE scripts more easily. Roughly it is a stack based
method system that deals with parallelism in the POE way.
Delay Garbage Collection (???)
POE's garbage collection can be slow. It would be very cool to
schedule this in the "dead" time between events. Especially in
instances where the next event is a timer and we have a few seconds of
nothing to do.
A lot of things rely on timely garbage collection, though. _parent
and _child events. Referential integrity. Things would be a mess
between _stop and the delayed garbage collection.
Delaying alarm GC might be doable. We can flag alarms as "dead" in
the ID->time hash and discard them as they come to the front of the
queue. In idle times when there are no FIFO events and the next alarm
is more than 1/10 second away, we can sweep the alarm queue and pull
out the dead ones.
It will take a fair amount of planning to pull this off correctly.
I'm just documenting it for now so I don't forget.
Clean up ASSERT_* and TRACE_* Flags
getting silly. Make this stuff macros, at the very least.
Batch or Standalone POE::Preprocessor
ActiveState's perlapp (PDK) does not recognize source filters and so
cannot "compile" POE programs into stand-alone applications. Source
filters may not be available elsewhere, so it would be useful to let
developers statically preprocess applications into stand-alone files.
This sort of preprocessing would kill the startup delay filters have
Known interested people: Ilya Melamed (he requested it)
Named State Parameters
Doable with backwards compatibility. Add a create-time option:
options => { named_parameters => 1 }
Which changes the dispatch semantics to hashref instead of arrayref.
Known interested people: Sungo, Coral, Artur, Lenzo
Pluggable Queue Disciplines
Add the ability to change the way events are dispatched. Priority
queues instead of FIFO, or something. Possibly a POE2 kind of thing.
Known interested people: Lenzo
Simplify Kernel
POE::Kernel originally managed events with a single queue. The queue
was split in two: FIFO for messages and a priority queue for timed
events. The split requires extra work in the main dispatch loop: the
loop must check two queues and dispatch events from each. It also
breaks determinism because timers and fifo messages can be dispatched
slightly out of order.
Steps to simplify queue management.
1. Recombine the queues.
This will reduce the amount of work needed to determine which event is
dispatched next.
The combine queue will be ordered by event time. FIFO events are
always enqueued for time(). Alarms and delays are enqueued for their
requested times.
2. Count pending FIFO events.
Manage an accumulator; increment it as FIFO events are enqueued, and
decrement it when they are dispatched.
This counter will allow the FIFO "enqueue" function to skip the head
of the queue. The first $count events (at least) will be before the
next FIFO slot.
3. Use the alarm enqueue function's optimizations.
The first, last, and middle-of-three checks short-circuit a lot of
cases. Binary seeking is O(log N) compares to find a place for the
next event. In the worst case, an insert will require O((log N)+3)
Binary seeking has a certain amount of overhead beyond linear seeking,
so it may be faster in some cases. Benchmark linear vs. binary
searches to get a feel for the break-even point between these two
styles. It may turn out that binary seeking just sucks.
Fracture Kernel
Split subsystems into submodules.
Programs can load only what they need. AUTOLOAD like.
Parts of POE can be replaced or overloaded, changing the way things
are done.
1. Find out if @ISA can be changed at runtime.
2. Figure out the logistics of adding code to existing
POE::Preprocessor macros. Modules may "hook" into macros by adding
new code at the end.
Event Dispatch Optimization: Multiple Dispatch
Multiple dispatch based on event type? Rather than big if/then trees
before and after the event is dispatched, break it into discrete
functions by event type. Create a dispatch table to call the proper
pre- and post-dispatch code.
$pre_dispatch{+ET_STOP} = \&pre_stop;
$post_dispatch{+ET_STOP} = \&post_stop;
It must be a hash because event types are bit flags. They get very
large, very fast, and I'm fairly certain perl doesn't do sparse arrays
Actually, they're bit flags because of the comparisons in the pre- and
post-dispatch if/then trees. The types can become an enumeration if
we switch to a dispatch table.
Instances where the caller knows what kind of event is being
dispatched (where _dispatch_state is called directly: call, and select
dispatches), the caller can call the proper pre- and post-dispatch
code itself. That will save a function call and two table lookups.
Macros will help keep this sort of thing maintainable.
Give Up 5.004 and 5.005
Perl 5.6.1 was released AGES ago, and there's talk of releasing a new
version. It's time to test the 5.6 waters. Try out new features, see
which hold water and which break and/or leak like nuts, and determine
how they can help.
Unfortunately, POE's used in production on 5.004 and/or 5.005 systems.
Adopting newer features will leave people behind. How can POE move on
without totally abandoning people?
Work Around Windows NT Socket Stupidity
Non-blocking connect() fails on Windows NT 4.0 and 5.0 (Windows 2000).
This is a departure from previous Windows sockets APIs, probably
related to the "overlapped" IO flag needing to be set.
People tell me I'm on crack when I mention that, though, despite the
symptoms matching exactly. Whatever. Meanwhile, I can skip
non-blocking connect() on those systems that don't support it anymore.
C:\>perl -MPOSIX -e "print join ':', uname()"
On 98:
Windows:bochs.homenet:4.10:Build 2222 ( A ):x86
On NT 4.0:
Windows NT:poeny:4.0:Build 1381 (Service Pack 6):x86
On 2000:
Windows NT:gil:5.0:Build 2195 (Service Pack 2):x86
But it will suck.
Stuff That's DONE
Improve Alarm Interface
This change adds new features without breaking the way old ones work.
1. Release a version with the new functions in place.
Done: 2001-07-15.
2. Optimize the new functions.
Done: 2001-07-26
I decided against using macros because bits of the alarm adjustment
code were different from the alarm setting code. The reason?
Adjusting an alarm doesn't have to look at the whole queue. It
only needs to look towards the beginning or end of the queue,
depending on the direction of the adjustment.
+ alarm_set(), alarm_adjust(), and alarm_remove() are done
+ delay_set() is done
+ alarm_remove_all() is done
- decided against alarm_remove_by_event(); use alarm() instead
- decided against alarm_remove_by time(); it's not very useful
Make Filter Changing Usable
This change adds new features without breaking existing ones. This
change is a prerequisite for input flow control in Wheel::ReadWrite.
2001-07-27 - Refactoring Checklist
1. get_one_start() takes an arrayref of chunks. It does not return
anything in particular.
done. documented.
2. get_one() returns an arrayref of 0 or 1 chunks. It does not take
anything. Actually, it can return 2+ chunks, but it tries to be
done. documented.
3. get_pending() returns undef if nothing is pending.
done. documented.
4. get_pending() returns an arrayref if something is pending. Check
for pending data using length(), defined(), or scalar() depending
on how the filter stores its pending data. Be sure not to test the
buffer directly for truth, as it may contain a significant 0 or
done. documented.
5. get_pending() does not damage a filter's buffer.
done. documented.
6. Wheels? Auuuugh!
Actually, only ReadWrite deals with filter changing. Whew!
done. documented.
7. Update Filter::Xyz documentation.
8. Update Wheel::Xyz documentation.
ReadWrite - done.
Finishing Touches:
Dear gods, some of this code sucks! The duplicated code in
Filter::Line is particularly horrific, not for its structure but
for the amount of duplication. The way wheels test for the end of
get_one() loops leaves much to be desired. But my brane is focused
on getting through this big suite of changes today, so I'm not
paying too much attention to doing it optimally. As my C guru once
said, "Get it working, and then make it faster."
Filter::Reference uses a hashref for its $self. Make that an
arrayref, damnit!
Once this is fixed, ReadWrite can use get_one() to fetch one event at
a time. The resume_input() method can, among other things, continue
the get_one() loop if data is already buffered but more isn't ready to
be read.
Released in version 0.1502.
Jump to Line
Something went wrong with that request. Please try again.