Tom Locke wrote: > > OK, here's what I'm hoping Parrot can provide for the language I'm building. > > My big requirement is for lightweight microthreads (hopefully *very* > lightweight - I'm considering one scheduler that can handle *millions* > of threads on a single machine).
Hmm, I can envision a microthread implementation wherein each microthread is nothing more than a Continuation PMC. Add an interpreter->microthreads PMC* pointer. (This could be a global stored in interpreter->perl_stash->stash_hash, but that wouldn't be as fast). Then, add the following ops: inline op init_microthreads() { if( !interpreter->microthreads ) interpreter->microthreads = new_pmc(interpreter, enum_class_PerlArray); goto NEXT(); } =item B<mthread_create>(in PMC) Create a new microthread, which will start with the Continuation in $1. =cut inline op mthread_create(in PMC) { VTABLE_push(interpreter, interpreter->microthreads, $1); goto NEXT(); } =item B<mthread_create>(inconst INT) Create a new Continuation, with the address set to $1, and =cut inline op mthread_create(inconst INT) { opcode_t *dest = PTR2OPCODE_T(CUR_OPCODE + $1)); PMC * p = new_ret_continuation_pmc(interpreter, dest) VTABLE_push(interpreter, interpreter->microthreads, p); goto NEXT(); } =item B<mthread_yieldcc>() Create a new Continuation (which resumes after this op), schedule it to activate later, and then switch to the next microthread. =cut inline op mthread_yieldcc() { opcode_t *dest = expr NEXT(); PMC * p = new_ret_continuation_pmc(interpreter, dest); VTABLE_push(interpreter, interpreter->microthreads, $1); p = VTABLE_shift(interpreter, interpreter->microthreads); dest = (opcode_t *)VTABLE_invoke(interpreter, p, dest); goto ADDRESS(dest); } =item B<mthread_yield>(in PMC) Schedule the Continuation in $1, then switch to the next microthread. =cut inline op mthread_yield(in PMC) { opcode_t *dest = expr NEXT(); PMC * p; VTABLE_push(interpreter, interpreter->microthreads, $1); p = VTABLE_shift(interpreter, interpreter->microthreads); dest = (opcode_t *)VTABLE_invoke(interpreter, p, dest); goto ADDRESS(dest); } =item B<mthread_yield>(inconst INT) Create a new Continuation, which resumes at address $1, then switch to the next microthread. =cut inline op mthread_yield(inconst INT) { opcode_t *dest = PTR2OPCODE_T(CUR_OPCODE + $1); PMC * p = new_ret_continuation_pmc(interpreter, dest); VTABLE_push(interpreter, interpreter->microthreads, p); p = VTABLE_shift(interpreter, interpreter->microthreads); dest = (opcode_t *)VTABLE_invoke(interpreter, p, dest); goto ADDRESS(dest); } inline op mthread_fork() { PMC * p = new_ret_continuation_pmc(interpreter, expr NEXT()); VTABLE_push(interpreter, interpreter->microthreads, p); goto NEXT() } > Oh and I will need them to be serializable. I hope you aren't planning on serializing just a single isolated microthread... that wouldn't work well with what I've got in mind due to how much stuff comes along when you serialize a continuation -- you'd get almost the whole interpreter serialized. If you want, instead, to serialize interpreter->microthreads, however... well, you'd *still* get almost the whole interpreter serialized, but you're getting more bang for your buck :) > I can live with co-operative scheduling, perhaps running > 'regular' threads over the top do provide a layer of preemptive > scheduling. Remember, each thread has it's own interpreter. This means that one would have to share ->microthreads amongst multiple interpreters. Besides the very minor nuisance of locking for ->push and ->shift, there's the very big headach of figuring out what happens when you invoke a continuation created in one interpreter in another interpreter. An easier solution might be to create a timer event which, when handled, does a yieldcc. [PS: All code in this message is UNTESTED. If you'd *like* to test, be my guest! :)] -- $a=24;split//,240513;s/\B/ => /for@@=qw(ac ab bc ba cb ca );{push(@b,$a),($a-=6)^=1 for 2..$a/6x--$|;print "[EMAIL PROTECTED] ]\n";((6<=($a-=6))?$a+=$_[$a%6]-$a%6:($a=pop @b))&&redo;}