Here is the current demo! It is very important to note how termination is handled!
To refresh your memory .. if you have any .. When you spawn an fthread it will block on an schannel operation until there is a matching operation: a read will block until there is a write, and a write until there is a read. This means to properly terminate a program, if you're using a driver loop, as with the event handling fthreads in the code below, you must organise a way to allow the fthread to terminate. Fthread can die in two ways: they can exit gracefully, by doing a usual return statement. Or they can suicide due to what would otherwise be a deadlock. A deadlock would occur if an schannel is reading (or writing) an schannel which no other active fthread can reach. to understand what happens: active fthreads (and ones waiting for async I/O) are GC roots. When you do a read or write on an schannel the fthread loses its root status. Instead, it is owned by the schannel! So if the schannel isn't reachable, the GC will reap the schannel AND the fthread. therefore: do NOT make global variables containing schannels, unless you're going to use them to satisfy I/O requests, otherwise the program will halt from starvation: the schannel and waiting thread are reachable but you're not sending them any messages! If you do have a global variable it is OK if you make sure the fthread on the other end of the schannel exits. If you do not take proper care, the program will either hang, or it will suicide. this is common! Getting a system of fthreads to terminate properly is non-trivial: you have to design the system to do it. Suicide is a normal and good design choice sometimes, however if you have to destroy some resource such as a window suicide probably isn't an option. You must always think; fthreads are NOT threads. They're just procedures which exchange control via schannels. And you must also remember: active fthreads OWN channels. Inactive fthreads are owned BY channels. Performing an I/O operation doesn't just exchange control .. it also exchanges ownership. Finally don't forget the mainline is just another fthread. There's nothing special about it (except that it returns implicitly when control drops of the end). ////////////////////////////////////////////////////////////////////// include "gui/__init__"; open FlxGui; // Initialise the SDL system (SDL + TTF + IMAGE) FlxGui::init(); // Make a window var w = window_t("My Window",50,50,400,400); // get a font, and the recommended vertical // spacing between lines var font : font_t = get_font(OSX_dflt_font()); var lineskip = get_lineskip font; // create some colours and clear the window var red = RGB(255,0,0); var green = RGB (0,255,0); w.clear green; // write some text and some lines w.write (100,100,font,red,"HELLO"); w.write (100,100+lineskip,font,red,"WORLD"); w.draw_line (RGB(0,0,255), 100,100,200,200); // update the window with the stuff we drew w.update; // create a window manager var wm = window_manager(); // get the channel to read events from var input = wm.get_event_source(); // make an event handler for our window proc ehandler (input:ischannel[event_t]) () { var run = true; while run do var e: event_t = read input; println$ " WINDOW specific EVENT: " + e.window.event.SDL_WindowEventID.str; run = e.window.event.SDL_WindowEventID != SDL_WINDOWEVENT_CLOSE ; done println$ "Terminating window event processing loop"; } // make a controller for the window using our event handler var wc = window_controller (w, ehandler); // place the controller under the window manager var i = wm.add_window wc; // report the index number of the window // indices allow us to loop over windows println$ "Window index " + i.str; // get a first event from the window manager var event : event_t = read input; // while the event isn't a quit event .. while event.type.SDL_EventType != SDL_QUIT do // print a diagnostic println$ event.type.SDL_EventType.str; // dispatch the event to the window it is associated with wm.dispatch_window_event event; // get another event event = read input; done // we must have got a quit .. println$ "QUIT EVENT"; var clock = Faio::mk_alarm_clock(); Faio::sleep(clock,10.0); begin for var j in 0 upto #(wm.get_n_windows) - 1 do // this is messy! Fix soon! var wc = wm.get_window_controller_from_index 0; var wid = #(wc.get_window_id); wm.delete_window wid; done end println$ "Windows deleted, quitting"; ////////////////////////////////////////////////////////////////////// One of the things that should start to become apparent with fthread/schannel design methodology is the total and utter decoupling of the components. Systems are made from totally independent "chips" which are though of as active processes that do I/O. The actual structure of the system (circuit board) requires wiring the chips together with schannels. This means, for example, if you have one or more window controllers, you can just plug multiple instances of them into the window manager. No extra work is required to do multiple windows. -- john skaller skal...@users.sourceforge.net http://felix-lang.org ------------------------------------------------------------------------------ _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language