Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 465 lines (400 sloc) 15.913 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
$Id$

A brief, pointless history of POE's evolution.

-------------------------------------------------------------------------------

Received: from sinistar.idle.com (sinistar.idle.com [198.109.160.36])
        by anshar.shadow.net (8.7.3/8.7.3) with ESMTP id JAA05315
        for <troc@shadow.net>; Fri, 7 Feb 1997 09:59:05 -0500 (EST)
Received: (from slist@localhost) by sinistar.idle.com (8.7.5/8.7.3)
        id JAA12501; Fri, 7 Feb 1997 09:00:15 -0500 (EST)
Resent-Date: Fri, 7 Feb 1997 09:00:15 -0500 (EST)
Message-Id: <199702071400.JAA00295@anshar.shadow.net>
From: "Rocco Caputo" <troc@shadow.net>
To: "Felix Gallo" <fgallo@wellspring.us.dg.com>,
        "perl5-porters@perl.org" <perl5-porters@perl.org>
Date: Fri, 07 Feb 97 08:54:23 -0400
Reply-To: "Rocco Caputo" <troc@shadow.net>
Priority: Normal
Subject: portable multithreading
Resent-Message-ID: <"O2kshC.A.W5C.lTz-y"@sinistar>
Resent-From: perl5-porters@perl.org
X-Mailing-List: <perl5-porters@perl.org> archive/latest/135
X-Loop: perl5-porters@perl.org
Precedence: list
Resent-Sender: perl5-porters-request@perl.org
Content-Type: text
Content-Length: 3989
Status:

On Thu, 06 Feb 1997 12:52:56 +0000, Felix Gallo wrote:

>Felix's Perl-related Metaproblems:
>
>1. Perl is not event-driven, so programs which wish
>to make objects available to the network must manually
>interrupt their control flow to determine if a remote
>object transaction request is pending.

I'm writing a MUD in perl. The object language faces
some of the same issues as perl, but I think there are
ways around them (in the MUD language and in perl). In
the MUD server, objects' methods must be compiled into
perl bytecode. They must be multitasked/multithreaded
so that bad code won't hang the server, and object
authors usually should not have to think about events.

For example, this "bad" MUD code will be legal. Don't
worry, I move on to perl in just a minute.

  count = 10000000
  while count--
    say "hello, world! enter some text: "
    getline some_text
    if some_text eq 'quit'
      last
    endif
  endwhile
  say "\ngoodbye, world!\n"

This needs to be compiled to perl bytecode at runtime.
The MUD bytecode compiler first parses and syntax
checks an object's source. If everything passes, it
builds a perl sub definition in a string. This
sub-in-a-string is treated as an assembly language for
perl bytecode. The server runs eval() to assemble the
string-o-perl into bytecodes, and then the resulting sub
can be called over and over without additional eval()
overhead. (Thanks, Silmaril!)

Making that bad loop work in an event-driven server is
a little harder than making bytecodes. The MUD compiler
will build perl assembly as event-driven state machines.
It can do this by noting the locations of branch
destinations and returns from blocking calls. Each of
these locations starts a new atomic "state", and an
"instruction pointer" determines which state to run next.

Here's the event-driven perl "assembly" for that sample
MUD code. It's not very efficient, but it serves for
illustration.

  sub aaaaa {
    # assumes the existence of a tasking/event kernel
    my $task = shift;
    my $namespace = $task->{"namespace"};
    my $ip = $task->{'instruction pointer'}; # state

    # initial entry point
    if ($ip == 0) {
      $namespace->{'count'} = 10000000 ;
      $task->{'instruction pointer'} = 1;
    }
    # top of while loop
    elsif ($ip == 1) {
      if ( $namespace->{'count'} -- ) {
        $task->say( qq(hello, world! enter some text: ) ) ;
        # soft block on 'getline'
        $task->{'blocking'} = 'getline';
        $task->{'instruction pointer'} = 2;
      }
      else {
        $task->{'instruction pointer'} = 3;
      }
    }
    # "return" from getline
    elsif ($ip == 2) {
      $namespace->{'some_text'} = $task->getline();
      if ( $namespace->{'some_text'} eq q(quit) ) {
        $task->{'instruction pointer'} = 3;
      }
      else {
        $task->{'instruction pointer'} = 1;
      }
    }
    # after endwhile
    elsif ($ip == 3) {
      $task->say( qq(\ngoodbye, world!\n) ) ;
      $task->{'instruction pointer'} = -1; # signals end
    }
  }

The main select/event loop would have some code to run tasks
round-robin. Something like this, but probably including code
to deal with priorities.

  if ($next = shift(@task_queue)) {
    if (($next->{'blocking'}) || ($next->run() != -1)) {
      push(@task_queue, $next);
    }
    else {
      undef $next;
    }
  }

And starting a new task might look like this:

  $task = new Task($tasking_kernel, "count = ... world!\n");
  if ($task->has_errors()) {
    $task->display_errors();
    undef $task;
  }
  # otherwise the task has been compiled and registered
  # with the $tasking_kernel

Anyway, that's how I'm writing portable multitasking for a
syntactically simple MUD language. To make this work for
perl, there would be a standard tasking package, and perl's
bytecode compiler would need to modify its output to work
with the package. Sort of like how the perl debugger works.

Just some ideas to ponder.

Rocco
<troc@shadow.net>

-------------------------------------------------------------------------------

Received: from sinistar.idle.com ([198.109.160.36])
        by anshar.shadow.net (8.8.5/8.7.3) with ESMTP id VAA13861
        for <troc@shadow.net>; Mon, 14 Apr 1997 21:04:07 -0400 (EDT)
Received: (from slist@localhost) by sinistar.idle.com (8.7.5/8.7.3)
        id UAA24149; Mon, 14 Apr 1997 20:37:16 -0400 (EDT)
Resent-Date: Mon, 14 Apr 1997 20:37:16 -0400 (EDT)
Message-Id: <199704150040.UAA11517@anshar.shadow.net>
From: "Rocco Caputo" <troc@shadow.net>
To: "Gary Howland" <gary@systemics.com>,
        "Tom Christiansen" <tchrist@jhereg.perl.com>
Cc: "Gary Howland" <gary@systemics.com>, "Hugo van der Sanden" <hv@iii.co.uk>,
        "hv@tyree.iii.co.uk" <hv@tyree.iii.co.uk>,
        "perl5-porters@perl.org" <perl5-porters@perl.org>
Date: Mon, 14 Apr 97 20:34:01 -0500
Reply-To: "Rocco Caputo" <troc@shadow.net>
Priority: Normal
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: Re: Perl5.005 wish list (event loop)
Resent-Message-ID: <"99mWD.A.PzF.i0sUz"@sinistar>
Resent-From: perl5-porters@idle.com
X-Mailing-List: <perl5-porters@idle.com> archive/latest/6171
X-Loop: perl5-porters@idle.com
Precedence: list
Resent-Sender: perl5-porters-request@idle.com
Content-Type: text/plain; charset="iso-8859-1"
Content-Length: 1119
Status:

Gary, et al,

Almost a year ago, I quietly announced something called "Serv + Face".
Maybe my announcement was a little too quiet.

Serv is a fork-less, select-based framework of event server classes.
It provides a high level interface to select(), and a very high level
interface to TCP client and server socket operations. It does not fork.

Face is the start of a curses-based UI framework that can run alone
or use Serv as its main loop.

The code and a rough draft of the documentation are available from
<http://www.shadow.net/~troc/perlstuff.html>. If this code is useful
to anyone, I'd sure like to know.

Rocco
<troc@shadow.net>

On Tue, 15 Apr 1997 01:36:35 +0200, Gary Howland wrote:
>
>Select is fine. What we (the "event evangelists") want is a "level above"
>select. When we have a chunk of data to send to x streams, we don't want to
>have to call select, see which stream is ready for writing, work out how
>many bytes we can send, send those bytes, shorten our buffers by that amount
>of bytes, and loop back to select. We just want to send the data. And we
>want to do this without forking.

-------------------------------------------------------------------------------

Received: from sinistar.idle.com (sinistar.idle.com [198.109.160.36])
        by anshar.shadow.net (8.7.3/8.7.3) with ESMTP id JAA04948
        for <troc@shadow.net>; Fri, 7 Feb 1997 09:54:31 -0500 (EST)
Received: (from slist@localhost) by sinistar.idle.com (8.7.5/8.7.3)
        id JAA12519; Fri, 7 Feb 1997 09:00:19 -0500 (EST)
Resent-Date: Fri, 7 Feb 1997 09:00:19 -0500 (EST)
Message-Id: <199702071400.JAA00339@anshar.shadow.net>
From: "Rocco Caputo" <troc@shadow.net>
To: "Felix Gallo" <fgallo@wellspring.us.dg.com>,
        "perl5-porters@perl.org" <perl5-porters@perl.org>
Date: Fri, 07 Feb 97 08:54:31 -0400
Reply-To: "Rocco Caputo" <troc@shadow.net>
Priority: Normal
Subject: polytheistic perl references
Resent-Message-ID: <"1y3hHB.A.w5C.sTz-y"@sinistar>
Resent-From: perl5-porters@perl.org
X-Mailing-List: <perl5-porters@perl.org> archive/latest/136
X-Loop: perl5-porters@perl.org
Precedence: list
Resent-Sender: perl5-porters-request@perl.org
Content-Type: text
Content-Length: 1502
Status:

On Thu, 06 Feb 1997 12:52:56 +0000, Felix Gallo wrote:

>Felix's Perl-related Metaproblems:
>
>3. Perl references are monotheistic. One fancies that saying
>$x = \{ http://perl.com/myperlobject }; would do the right thing,
>but the established structure of Perl seems to make this difficult.

There are tied hash packages that implement object naming
and message passing between named objects within the same
process. The packages allow invocations like:

  $msg{'desktop,paint'} = 1;
  $msg{'name entry,value'} = 'J. K. Cohen';
  $active_flag = $msg{'active checkbox,value'};

The packages also do broadcasting to subsets of the object
dictionary. Hash stores and fetches are sent to or taken
from all the objects that match the supplied name. So to
clear the value of all objects that have 'entry' in their
names:

  $msg{'entry,value'} = '';

That clears 'name entry' and 'age entry' and 'salary entry'
and ....

Anyway, the names could be extended to work across sockets
in the presence of a standard select/event loop:

  $gnats_queue = $msg{'//somewhere.com:4242/stickynote/gnat?count'};
  print "gnat has $gnats_queue unread sticky notes.\n";

  $message = 'hello, world!';
  $msg{'//somewhere.org:4242/stickynote/merlyn?queue'} = $message;

Man pages for ObjDict::Names and ObjDict::Messages are
on-line at <http://www.nexi.com/troc>. The code is inside
a larger package, Serv+Face, at
<http://www.shadow.net/~troc/perlstuff.html>.

Just some ideas to ponder.

Rocco
<troc@shadow.net>

-------------------------------------------------------------------------------

This is a header from a program I was writing before I discovered Perl.

// =========================================================================
// UBERSYS.H
// UberSys definitions and classes.
// =========================================================================

#include <io.h>
#include <dir.h>
#include <dos.h>
#include <math.h>
#include <time.h>
#include <alloc.h>
#include <conio.h>
#include <ctype.h>
#include <fcntl.h>
#include <share.h>
#include <stdio.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <values.h>
#include <fstream.h>
#include <iomanip.h>
#include <iostream.h>
#include <sys\stat.h>

// -------------------------------------------------------------------------
// Constants, limits, and the like.

#define SIZE_UID 9 // including NULL terminator
#define SIZE_PWD 26 // including NULL terminator
#define SIZE_MAXSTR 0x1000 // 4k string sizes (max)
#define SIZE_MAXPATH 0x0050 // 160 chars for max path
#define SIZE_MAXLINE 0x00A0 // 160 characters per line
#define COUNT_LINES 0x0200 // 512 editor lines

#define USREV 0x0200 // version 02.00

#define DRV "D:" // drive it runs on

// -------------------------------------------------------------------------
// Helper macros.
                                        // build a 20-bit address from segoff
#define A20(x) (((ULI)FP_SEG(x)<<4)+(ULI)FP_OFF(x))
                                        // make a normalized pointer from A20
#define A32(x) MK_FP((UINT)((x)>>4), (UINT)((x)&0x0F))
                                        // normalize a far pointer using A20
#define NORM(x) A32(A20(x))
                                        // maximum of two values
template <class T>
T max(T x, T y)
{
        return((x>y)?x:y);
};
                                        // minimum of two values
template <class T>
T min(T x, T y)
{
        return((x<y)?x:y);
};
                                        // inline assembly shorthand
#define I asm

#define FATAL fatalerr(thisFile,__LINE__)
#define FATALH(x) fatalerr(x,__LINE__)

#if defined(DEBUG)
# define ERRS if(errorstream)*errorstream<<setiosflags(ios::uppercase)<<hex
# define CRV(x) if((x)==RV_FAILURE)FATAL
# define CNE(x) if((x)==-1)FATAL
# define CZE(x) if(!(x))FATAL
# define FLINE ,thisFile,__LINE__
# define FLINC thisFile,__LINE__
# define FLINP , char *file, int line
# define FLINQ char *file, int line
# define FLINI ,file,line
# define FLINJ file,line
# define FLINS thisFile,__LINE__,
# define FLINT char *file, int line,
# define FLI dec<<");\t\t// f:"<<setw(12)<<file<<" @ l:"<<setw(4)<<line
# define BOTH(x) A20(x)<<" ["<<A20(*(x))<<"]"
# define DEB(x) x
# define DEB2(x,y) x,y
# define NEW ERRS<<dec<<"\nCall to new.\t\t\t\t\t// f:"<<setw(12)<<thisFile<<" @ l:"<<setw(4)<<__LINE__;
# define DEL ERRS<<dec<<"\nCall to delete.\t\t\t\t\t// f:"<<setw(12)<<thisFile<<" @ l:"<<setw(4)<<__LINE__;
# define WHEREAMI ERRS<<dec<<"\nInside file "<<thisFile<<" @ line "<<__LINE__;
# define ORPHANS { ERRS<<dec<<"\nOrphan check in "<<thisFile<<" @ line "<<__LINE__<<". "; CRV(aOrphans(FLINC)); }
# define VALID(dp) CZE(aValid(aHeader(dp)));
# define DUMP aDump(FLINC);
#else
# define ERRS cerr
# define CRV(x) x
# define CNE(x) x
# define FLINE
# define FLINC
# define FLINP
# define FLINQ void
# define FLINI
# define FLINJ
# define FLINS
# define FLINT
# define DEB(x)
# define DEB2(x,y)
# define NEW
# define DEL
# define WHEREAMI
# define ORPHANS
# define VALID(dp)
# define DUMP
#endif

#define FALSE 0
#define TRUE (~FALSE)

// -------------------------------------------------------------------------

void fatalerr(char *file, int line);

extern char *buildbuf;

// -------------------------------------------------------------------------
                                        // Paradox Engine header
#include "pxengine.h"
                                        // Error stream if debugging.
DEB(extern ofstream *errorstream;)
                                        // Message file header.
#include "general.h"
                                        // Type definitions.
#include "mytypes.h"
                                        // Database functions.
#include "pxe.h"
#include "users.h"
#include "ipx.h"
                                        // Code groups.
#include "pcodes.h"
#include "gsbl.h"
#include "arena.h"
#include "interrup.h"
#include "port.h"
#include "msgfile.h"
#include "task.h"
#include "tam.h"
#include "qualpath.h"
#include "xmm.h"
#include "var.h"
#include "safepxi.h"
#include "template.h"
#include "token.h"
#include "stack.h"
#include "objfile.h"
#include "ofm.h"
#include "srcfile.h"
#include "pmachine.h"
                                        // BBS modules.
#include "hangup.h"
#include "idle.h"
#include "login.h"
#include "editor.h"
#include "cmdline.h"
#include "console.h"
#include "dirlist.h"
#include "compiler.h"
#include "disasm.h"
#include "runtime.h"

// -------------------------------------------------------------------------

extern TAM *tam;

-------------------------------------------------------------------------------

Light was let be.
Something went wrong with that request. Please try again.