Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

912 lines (653 sloc) 32.777 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.
Depreciations & 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.
Depreciate 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() depreciated 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 depreciation 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.
Make Filter Changing Usable
This change adds new features without breaking existing ones.
2001-07-27 - Refactoring Checklist
1. get_one_start() takes an arrayref of chunks. It does not return
2. get_one() returns an arrayref of 0 or 1 chunks. It does not take
3. get_pending() returns undef if nothing is pending.
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 directyl for truth, as it may contain a significant 0 or
5. get_pending() does not damage a filter's buffer.
6. Wheels? Auuuugh!
7. Update Wheel::Xyz and Filter::Xyz documentation.
+ Block
+ Grep
+ Line
+ Map
+ RecordBlock
+ Reference
+ Stackable
+ Stream
+ ReadWrite
Finishing Touches:
Dear gods, some of this code sucks! The duplicated code in
Filter::Line is particularly horrific. 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.
Depreciations & 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 depreciation 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. :)
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. Depreciate (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.
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.
Wheel::ReadWrite Needs Input Flow Control
This change depends on fixed filter changing.
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!
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?
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.
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.
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 - One Idea
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 - Two Idea
use POE::Tweak qw( Trace => qw( +default -garbage ),
Assert => qw( +default -reference ),
Tweaks would be global.
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
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()
* 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 depreciation 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.
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 depreciate 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 depreciation 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 depreciation is proceding apace.
* Wait at least 28 days after releasing the warnings (until
????.??.??) before continuing this depreciation 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 depreciation has completed.
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.
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.
Let Ilya Melamed know when this is done. It's his request.
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
Jump to Line
Something went wrong with that request. Please try again.