On 31 March 2011 08:15, john skaller <skal...@users.sourceforge.net> wrote: > > On 31/03/2011, at 3:17 AM, Rhythmic Fistman wrote: > >> On 30 March 2011 18:00, john skaller <skal...@users.sourceforge.net> wrote: >>> >>> On 31/03/2011, at 2:15 AM, Rhythmic Fistman wrote: >>> >>>> >>>> Thanks! Now I've got my felix code compiling to cpp again, using the >>>> 2007 version of flxcc to generate the massive enum. Now to unbreak my >>>> custom driver. >>> >>> >>> Why not use the standard one? >> >> Because I'm embedding felix in c++ and not vice versa. >> My driver is synchronous, and returns control to the embedder once all >> fthreads have called a sleep function. It basically lets me run "one >> tick" worth of embedded fthreads at a time. > > Well, we should be able to make flx_run do that too.
I would love to get rid of the custom driver, it's a pain to maintain. > It already knows when there's nothing to do (you don't need to call a sleep > function), and it already exits when that happens. > > The difference is that when there's nothing to do its all over, > so we need to fix that. Also we don't want to exit entirely > and lose the gc objects etc. I could factorise flx_run.include. Here's what my driver's interface looks like: #ifndef __FLX_SYNC_DRIVER__ #define __FLX_SYNC_DRIVER__ // alternative driver that uses the newly factored sync state. this allows // us to use sync channels and all sorts of great stuff. class flx_sync_driver { void* opaque; public: flx_sync_driver(); ~flx_sync_driver(); // void spawn(int argc, char** argv); // does one cycle (until finished, or all threads blocked) // returned fthread is currently just a pointer, so be careful of its // scope lest you deschedule the wrong fthread. void spawn(void *con, void** out_ft = 0); bool deschedule(void* ft); // an fthread* bool run(); void* ptf(); // a.k.a get_ptf }; #endif There's nothing special there - I spawn fthreads from outside of felix via flx exports and occasionally deschedule fthreads that haven't exited naturally. The "real" driver is an opaque blob inside that contains the gc data, and active fthreads. It also contains a "ticker", a felix schannel[int] that when read from returns the current tick (of the game - it's a game). The tick is actually ignored; reading only serves to deschedule the fthread until the next tick. class sync_drv_data { public: felix_vars fv; // collector, link info. flx::gc::generic::gc_profile_t gcp; std::list<fthread_t*> active; flx::run::sync_state_t ss; //flx::rtl::flx_libinit_t instance; thread_frame_t* ptf; // todo: use rtl macros, make argc defined // folks sleep on this. I used to add this as a root even though the // gc didn't create it. That turned out to be Not Cool. Now it's a // pointer created by the gc then added as a root. // is that a problem? // flx::rtl::schannel_t ticker; flx::rtl::schannel_t* m_ticker; // grabbed from thread frame bool* m_quit_flag; // grabbed from thread frame int ticker_value; sync_drv_data(); ~sync_drv_data(); void spawn(con_t* c, fthread_t** out_ft); bool deschedule(fthread_t* ft); // hmmm bool run(); // returns still going flag int unblock_all(); // free from ticker }; Later the driver unblocks the fthreads by simulating n channel writes: // returns num threads unblocked. // manually simulates a completed write on each of the readers of the // ticker channel. I tried to rewrite this in felix, but that proved // difficult as the real write unscheduled the writer, which didn't // clear the list of readers. int sync_drv_data::unblock_all() { // fprintf(stderr, "activating in correct order?\n"); fthread_t* reader; int n = 0; // simulates an fthread writing enough times to wake all on ticker. // tricky. whilst blocked on the driver's ticker the threads are not // referenced. For this the ticker itself is rooted. while((reader = m_ticker->pop_reader())) // all must read from ticker { _uctor_* svc = reader->get_svc(); assert(svc_sread == svc->variant); readreq_t * pr = (readreq_t*)svc->data; *(void**)pr->variable = &ticker_value; // I'm pretty sure these guys activate in the order they slept active.push_front(reader); fv.collector.add_root(reader); n++; } ticker_value++; // someone might use this value one day return n; } I tried to implement this step in felix: gen has_reader[t]: schannel[t] -> bool = "$1->waiting_to_read->head != NULL"; // this isn't quite working, can't be run by simple continuation execution, // needs own svc savvy driver, which is a bit too second order for me. also // getting gc error: "removed non root". private proc flx_unblock_all(tick: int, npopped: &int) { var n = 0; while{ has_reader(ticker) } { // peek readers so we don't desched n++; write(ticker, tick); // pop a reader }; *npopped = n; } but it never quite worked. That would have been nice as it's one of the most complicated parts of the driver. The rest was bookkeeping. What do you think? RF PS I hope gmail screws my formatting up. > > > -- > john skaller > skal...@users.sourceforge.net > > > > > ------------------------------------------------------------------------------ Create and publish websites with WebMatrix Use the most popular FREE web apps or write code yourself; WebMatrix provides all the features you need to develop and publish your website. http://p.sf.net/sfu/ms-webmatrix-sf _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language