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

Reply via email to