1.3. Universal Program Driver

This driver runs stand alone Felix programs. It invokes the library routine 'start'. No messages are dispatched, the Felix program must not read any messages.

For statically linked programs, command line arguments are passed directly, the debugging switch isn't supported.

For dynamically loaded programs, the name of the driver and optional --debug switch given before the shared library name are not passed.

Start cpp section to rtl/flx_async.hpp[1 /1 ]
     1: #line 2350 "./lpsrc/flx_rtl.pak"
     2: #ifndef __FLX_ASYNC_H__
     3: #define __FLX_ASYNC_H__
     4: #include "flx_rtl_config.hpp"
     5: #include "flx_rtl.hpp"
     6: 
     7: #ifdef BUILD_ASYNC
     8: #define ASYNC_EXTERN FLX_EXPORT
     9: #else
    10: #define ASYNC_EXTERN FLX_IMPORT
    11: #endif
    12: 
    13: // GLOBAL NAMESPACE!
    14: 
    15: class ASYNC_EXTERN async_hooker {
    16: public:
    17:   virtual flx::rtl::fthread_t *dequeue()=0;
    18:   virtual void handle_request(void *data, flx::rtl::fthread_t *ss)=0;
    19:   virtual ~async_hooker();
    20: };
    21: 
    22: typedef
    23: async_hooker *
    24: create_async_hooker_t
    25: (
    26:   int n0,   // bound on resumable thread queue
    27:   int n1,   // bound on general input job queue
    28:   int m1,   // number of threads in job pool
    29:   int n2,   // bound on async fileio job queue
    30:   int m2    // number of threads doing async fileio
    31: );
    32: 
    33: extern "C" {
    34: ASYNC_EXTERN async_hooker *
    35: create_async_hooker
    36: (
    37:   int n0,   // bound on resumable thread queue
    38:   int n1,   // bound on general input job queue
    39:   int m1,   // number of threads in job pool
    40:   int n2,   // bound on async fileio job queue
    41:   int m2    // number of threads doing async fileio
    42: );
    43: }
    44: 
    45: #endif
End cpp section to rtl/flx_async.hpp[1]
Start cpp section to rtl/flx_async.cpp[1 /1 ]
     1: #line 2397 "./lpsrc/flx_rtl.pak"
     2: #include "flx_async.hpp"
     3: #include "pthread_sleep_queue.hpp"
     4: #include "flx_rtl.hpp"
     5: #include "demux_demuxer.hpp"
     6: #include "faio_asyncio.hpp"
     7: #include "pthread_thread.hpp"
     8: 
     9: using namespace flx::rtl;
    10: using namespace flx::demux;
    11: using namespace flx::pthread;
    12: using namespace flx::faio;
    13: 
    14: 
    15: class async_hooker_impl : public async_hooker {
    16: public:
    17:   void handle_request(void *data,fthread_t *ss);
    18:   virtual sleep_queue_t *get_ready_queue()=0;
    19:   ~async_hooker_impl();
    20: };
    21: 
    22: 
    23: #include "faio_asyncio.hpp"
    24: 
    25: async_hooker::~async_hooker(){
    26:  //fprintf(stderr,"Deleted async_hooker\n");
    27: }
    28: 
    29: async_hooker_impl::~async_hooker_impl(){
    30:   //fprintf(stderr,"Deleted async_hooker_impl\n");
    31: }
    32: 
    33: void async_hooker_impl::handle_request(void *data,fthread_t *ft)
    34: {
    35:   flx::faio::flx_driver_request_base* dreq =
    36:         (flx::faio::flx_driver_request_base*)data
    37:   ;
    38: 
    39:   //fprintf(stderr,"Request object at %p\n",dreq);
    40:   // RF hates the flag this function returns .. might
    41:   // mask a race condition, get rid of it
    42: 
    43:   finote_t *fn = new wakeup_fthread_t(get_ready_queue(),ft);
    44:   //fprintf(stderr,"async hooker dispatching request %p, fn = %p\n",dreq,fn);
    45:   dreq->start_async_op(fn);
    46: }
    47: 
    48: class proto_async : public async_hooker_impl
    49: {
    50:     sleep_queue_t async_active;
    51: 
    52: public:
    53:    proto_async(int n0, int n1, int m1, int n2, int m2) :
    54:      async_active(n0)
    55:    {
    56:    }
    57: 
    58:   ~proto_async(){
    59:     //fprintf(stderr,"Deleting proto async\n");
    60:   }
    61:   sleep_queue_t *get_ready_queue() { return &async_active; }
    62:   fthread_t* dequeue()
    63:   {
    64:     return (fthread_t*)async_active.dequeue();
    65:   }
    66: };
    67: 
    68: async_hooker *create_async_hooker(int n0,int n1,int m1,int n2,int m2) {
    69:   return new proto_async(n0,n1,m1,n2,m2);
    70: }
End cpp section to rtl/flx_async.cpp[1]
Start cpp section to rtl/flx_eh.hpp[1 /1 ]
     1: #line 2469 "./lpsrc/flx_rtl.pak"
     2: #ifndef __FLX_EH_H__
     3: #define __FLX_EH_H__
     4: #include "flx_rtl_config.hpp"
     5: #include "flx_rtl.hpp"
     6: 
     7: namespace flx { namespace rtl {
     8: void RTL_EXTERN print_loc(FILE *ef,flx::rtl::flx_range_srcref_t x,char *cf, int cl);
     9: int RTL_EXTERN std_exception_handler (std::exception *e);
    10: int RTL_EXTERN flx_exception_handler (flx::rtl::flx_exception_t *e);
    11: }}
    12: 
    13: #endif
    14: 
End cpp section to rtl/flx_eh.hpp[1]
Start cpp section to rtl/flx_eh.cpp[1 /1 ]
     1: #line 2483 "./lpsrc/flx_rtl.pak"
     2: #include <stdio.h>
     3: #include "flx_rtl.hpp"
     4: #include "flx_dynlink.hpp"
     5: #include "flx_eh.hpp"
     6: using namespace flx::rtl;
     7: 
     8: void flx::rtl::print_loc(FILE *ef,flx_range_srcref_t x,char *cf, int cl)
     9: {
    10:   fprintf(ef,"Felix location: %s %d[%d]-%d[%d]\n",
    11:     x.filename,
    12:     x.startline,
    13:     x.startcol,
    14:     x.endline,
    15:     x.endcol
    16:   );
    17:   fprintf(ef,"C++ location  : %s %d\n", cf, cl);
    18: }
    19: 
    20: 
    21: int flx::rtl::std_exception_handler (std::exception *e)
    22: {
    23:   fprintf(stderr,"C++ STANDARD EXCEPTION %s\n",e->what());
    24:   return 4;
    25: }
    26: 
    27: int flx::rtl::flx_exception_handler (flx_exception_t *e)
    28: {
    29:   if (flx_halt_t *x = dynamic_cast<flx_halt_t*>(e))
    30:   {
    31:     fprintf(stderr,"Halt: %s \n",x->reason.data());
    32:     print_loc(stderr,x->flx_loc,x->cxx_srcfile, x->cxx_srcline);
    33:     return 3;
    34:   }
    35:   if (flx_link_failure_t *x = dynamic_cast<flx_link_failure_t*>(e))
    36:   {
    37:     fprintf(stderr,"Dynamic linkage error\n");
    38:     fprintf(stderr,"filename: %s\n",x->filename.data());
    39:     fprintf(stderr,"operation: %s\n",x->operation.data());
    40:     fprintf(stderr,"what: %s\n",x->what.data());
    41:     return 2;
    42:   }
    43:   else
    44:   if (flx_exec_failure_t *x = dynamic_cast<flx_exec_failure_t*>(e))
    45:   {
    46:     fprintf(stderr,"Execution error\n");
    47:     fprintf(stderr,"filename: %s\n",x->filename.data());
    48:     fprintf(stderr,"operation: %s\n",x->operation.data());
    49:     fprintf(stderr,"what: %s\n",x->what.data());
    50:     return 3;
    51:   }
    52:   else
    53:   if (flx_assert_failure_t *x = dynamic_cast<flx_assert_failure_t*>(e))
    54:   {
    55:     fprintf(stderr,"Assertion Failure\n");
    56:     print_loc(stderr,x->flx_loc,x->cxx_srcfile, x->cxx_srcline);
    57:     return 3;
    58:   }
    59:   else
    60:   if (flx_assert2_failure_t *x = dynamic_cast<flx_assert2_failure_t*>(e))
    61:   {
    62:     fprintf(stderr,"Assertion2 Failure\n");
    63:     print_loc(stderr,x->flx_loc,x->cxx_srcfile, x->cxx_srcline);
    64:     print_loc(stderr,x->flx_loc2,x->cxx_srcfile, x->cxx_srcline);
    65:     return 3;
    66:   }
    67:   else
    68:   if (flx_match_failure_t *x = dynamic_cast<flx_match_failure_t*>(e))
    69:   {
    70:     fprintf(stderr,"Match Failure\n");
    71:     print_loc(stderr,x->flx_loc,x->cxx_srcfile, x->cxx_srcline);
    72:     return 3;
    73:   }
    74:   if (flx_range_failure_t *x = dynamic_cast<flx_range_failure_t*>(e))
    75:   {
    76:     fprintf(stderr,"Range Check Failure\n");
    77:     print_loc(stderr,x->flx_loc,x->cxx_srcfile, x->cxx_srcline);
    78:     return 3;
    79:   }
    80:   else
    81:   {
    82:     fprintf(stderr,"Unknown EXCEPTION!\n");
    83:     return 5;
    84:   }
    85: }
End cpp section to rtl/flx_eh.cpp[1]
Start cpp section to rtl/flx_run.include[1 /1 ]
     1: #line 2570 "./lpsrc/flx_rtl.pak"
     2: #include <cstdlib>
     3: #include <stdio.h>
     4: #include <vector>
     5: #include <list>
     6: #include <map>
     7: #include <cstring>
     8: #include <cassert>
     9: 
    10: #include <string>
    11: //#include <unistd.h>
    12: 
    13: #include "flx_rtl.hpp"
    14: #include "flx_async.hpp"
    15: #include "flx_ts_collector.hpp"
    16: #include "flx_dynlink.hpp"
    17: #include "flx_sync.hpp"
    18: #include "pthread_thread.hpp"
    19: #include "pthread_counter.hpp"
    20: #include "flx_eh.hpp"
    21: 
    22: using namespace std;
    23: using namespace flx::rtl;
    24: using namespace flx::pthread;
    25: using namespace flx::run;
    26: 
    27: #if FLX_HAVE_GNU_X86
    28: register void *sp __asm__("esp");
    29: #elif FLX_HAVE_GNU_X86_64
    30: register void *sp __asm__("rsp");
    31: #else
    32: static void *sp = 0;
    33: #endif
    34: 
    35: // non async drivers aren't don't depend on faio<-demux<-winsock
    36: // and so aren't linked with mswsock and ws2_32
    37: #if FLX_WIN32 && FLX_SUPPORT_ASYNC
    38:   #include "demux_iocp_demuxer.hpp"
    39:   // needed to perform win socket io (calls WSAInit). Must happen
    40:   // before iocp_demuxer is instantiated and (I assume) happen
    41:   // only once.
    42:   // JS: No, it can be called any number of times, provided
    43:   // the destructor WSACleanup is called same number of times
    44:   // Use of this RAII object ensures WSAinit/Cleanup calls balance.
    45:   // RF: Still has to happen before any socket calls. Putting it in
    46:   // the async object which is created on command is already too late.
    47:   // If that's a problem then any socket creation calls would have to
    48:   // gratuitously make async calls.
    49:   flx::demux::winsock_initer wsinit;
    50: #endif
    51: 
    52: 
    53: int do_final_cleanup(
    54:   bool debug_driver,
    55:   gc_profile_t *gcp,
    56:   flx_dynlink_t *library,
    57:   flx_libinit_t *instance
    58: );
    59: 
    60: class thread_control_t
    61: {
    62:     unsigned int thread_counter;
    63:     bool do_world_stop;
    64:     flx_condv_t stop_guard;
    65:     flx_mutex_t stop_mutex;
    66: public:
    67:     thread_control_t () : do_world_stop(false), thread_counter(0)
    68:     {
    69:       //fprintf(stderr,"INITIALISING THREAD CONTROL OBJECT\n");
    70:     }
    71: 
    72:     int thread_count() {
    73:       flx_mutex_locker_t m(stop_mutex);
    74:       return thread_counter;
    75:     }
    76: 
    77:     void add_thread() {
    78:       flx_mutex_locker_t m(stop_mutex);
    79:       //fprintf(stderr, "Adding thread\n");
    80:       ++thread_counter;
    81:       stop_guard.broadcast();
    82:     }
    83:     void remove_thread() {
    84:       flx_mutex_locker_t m(stop_mutex);
    85:       //fprintf(stderr, "Removing thread\n");
    86:       --thread_counter;
    87:       stop_guard.broadcast();
    88:     }
    89: 
    90:     // stop the world!
    91:     bool world_stop() {
    92:       flx_mutex_locker_t m(stop_mutex);
    93:       //fprintf(stderr,"Stopping world\n");
    94:       if (do_world_stop) return false; // race! Someone else beat us
    95:       do_world_stop = true;
    96:       --thread_counter;
    97:       while(thread_counter>0) stop_guard.wait(&stop_mutex);
    98:       //fprintf(stderr,"World STOPPED\n");
    99:       return true; // we stopped the world
   100:     }
   101: 
   102:     // used by mainline to wait for other threads to die
   103:     void join_all()
   104:     {
   105:       flx_mutex_locker_t m(stop_mutex);
   106:       while(do_world_stop || thread_counter>0) stop_guard.wait(&stop_mutex);
   107:       //fprintf(stderr,"World restarted: do_world_stop=%d, Yield thread count now %d\n",do_world_stop,thread_counter);
   108:     }
   109: 
   110:     // restart the world
   111:     void world_start() {
   112:       flx_mutex_locker_t m(stop_mutex);
   113:       //fprintf(stderr,"Restarting world\n");
   114:       ++thread_counter;
   115:       do_world_stop = false;
   116:       stop_guard.broadcast();
   117:     }
   118: 
   119:    void yield() {
   120:       flx_mutex_locker_t m(stop_mutex);
   121:       if (do_world_stop)
   122:       {
   123:         //fprintf(stderr,"Yield found world stop!\n");
   124:         --thread_counter;
   125:         //fprintf(stderr,"Yield thread count now %d\n",thread_counter);
   126:         stop_guard.broadcast();
   127:         while(do_world_stop) stop_guard.wait(&stop_mutex);
   128:         ++thread_counter;
   129:         //fprintf(stderr,"World restarted: do_world_stop=%d, Yield thread count now %d\n",do_world_stop,thread_counter);
   130:       }
   131:    }
   132: };
   133: 
   134: 
   135: struct doflx_data
   136: {
   137:   bool debug_driver;
   138:   gc_profile_t *gcp;
   139:   std::list<fthread_t*> *active;
   140:   thread_control_t *thread_control;
   141:   doflx_data(bool d, gc_profile_t *g, std::list<fthread_t*> *a, thread_control_t *tc)
   142:    : debug_driver(d), gcp(g), active(a), thread_control(tc) {}
   143: };
   144: 
   145: static
   146: create_async_hooker_t *ptr_create_async_hooker = NULL;
   147: 
   148: void doflx (void *data) {
   149:   doflx_data *d = (doflx_data*)data;
   150:   bool debug_driver = d->debug_driver;
   151:   gc_profile_t *gcp = d-> gcp;
   152:   std::list<fthread_t*> *active = d->active;
   153:   thread_control_t *thread_control=d->thread_control;
   154:   delete d;
   155: 
   156:   unsigned long async_count = 0;
   157:   async_hooker* async = NULL;
   158: 
   159:   try
   160:   {
   161:     sync_state_t ss(debug_driver, gcp, active);
   162: 
   163:   process_active:
   164:     if(debug_driver)fprintf(stderr,"Process active ..");
   165: 
   166:     if(debug_driver)
   167:       fprintf(stderr,"Before running: Sync state is %s/%s\n",
   168:         get_fstate_desc(ss.fs),get_fpc_desc(ss.pc));
   169: 
   170:     ss.frun();
   171: 
   172:     if(debug_driver)
   173:       fprintf(stderr,"After running: Sync state is %s/%s\n",
   174:         get_fstate_desc(ss.fs),get_fpc_desc(ss.pc));
   175: 
   176:     if (ss.fs == terminated) goto cleanup;
   177: 
   178:     //fprintf(stderr, "Thread yielding ..");
   179:     thread_control->yield();
   180:     //fprintf(stderr, "..Thread resuming!\n");
   181: 
   182:     if (ss.fs == blocked) goto do_async;
   183: 
   184:     if (ss.fs == delegated)
   185:     switch (ss.request->variant)
   186:     {
   187:       case svc_compact:
   188:       {
   189:         // requires fthreads to be immobile
   190:         if(debug_driver)fprintf(stderr,"svc compact\n");
   191:         gcp->collector->compact(false);
   192:       }
   193:       goto process_active;
   194: 
   195:       case svc_collect:
   196:       {
   197:         // requires fthreads to be immobile
   198:         if(debug_driver)fprintf(stderr,"svc collect\n");
   199:         if (thread_control->world_stop())
   200:         {
   201:           if(debug_driver)fprintf(stderr,"ACTUALLY COLLECTING\n");
   202:           gcp->collector->collect();
   203:           thread_control->world_start();
   204:         }
   205:         else {
   206:           if(debug_driver)fprintf(stderr,"RACE: someone else is collecting, just yield\n");
   207:           thread_control->yield();
   208:         }
   209:       }
   210:       goto process_active;
   211: 
   212:       case svc_collect_and_compact:
   213:       {
   214:         // requires fthreads to be immobile
   215:         if(debug_driver)fprintf(stderr,"svc collect and compact\n");
   216:         if (thread_control->world_stop())
   217:         {
   218:           gcp->collector->collect();
   219:           gcp->collector->compact(true);
   220:           thread_control->world_start();
   221:         }
   222:         else thread_control->yield();
   223:       }
   224:       goto process_active;
   225: 
   226:       case svc_spawn_pthread:
   227:       {
   228:         fthread_t *ftx = *(fthread_t**)ss.request->data;
   229:         if(debug_driver)fprintf(stderr,"Spawn pthread %p\n",ftx);
   230:         gcp->collector->add_root(ftx);
   231:         std::list<fthread_t*> *pactive =new std::list<fthread_t*>;
   232:         pactive->push_front(ftx);
   233:         void *data = new doflx_data(debug_driver, gcp, pactive, thread_control);
   234:         flx_detached_thread_t dummy;
   235:         if(debug_driver)fprintf(stderr,"Starting new pthread, thread counter= %ld\n",thread_control->thread_count());
   236:         thread_control->add_thread();
   237:         dummy.init( doflx,data);
   238:       }
   239:       goto process_active;
   240: 
   241:       case svc_general:
   242:       {
   243:         if(debug_driver)
   244:           fprintf(stderr,"svc_general from fthread=%p\n",ss.ft);
   245:         if( !async )
   246:         {
   247:           if (ptr_create_async_hooker == NULL)
   248:           {
   249: #if !FLX_SUPPORT_ASYNC
   250:              ptr_create_async_hooker = 0;
   251: #else
   252:              ptr_create_async_hooker = create_async_hooker;
   253:   #ifndef FLX_STATIC_LINK
   254:              LIBHANDLE async_lib = flx_load_module("libflx_async_dynamic");
   255:              if (async_lib == NULL)
   256:              {
   257:                fprintf(stderr,"Unable to find module 'libflx_async_dynamic'\n");
   258:                exit(1);
   259:              }
   260:              // debug only ..
   261:              else {
   262:                if(debug_driver)
   263:                  fprintf(stderr, "module 'libflx_async_dynamic' loaded!\n");
   264:              }
   265:              ptr_create_async_hooker = (create_async_hooker_t*)
   266:                DLSYM(async_lib,create_async_hooker)
   267:              ;
   268:              if (ptr_create_async_hooker == NULL)
   269:              {
   270:                fprintf(stderr,"Unable to find symbol 'create_async_hooker' in module 'libflx_async_dynamic'\n");
   271:                exit(1);
   272:              }
   273:              // debug only
   274:              else {
   275:                if(debug_driver)
   276:                  fprintf(stderr, "found 'create_async_hooker'!\n");
   277:              }
   278:   #endif
   279: #endif
   280:           }
   281:           if (ptr_create_async_hooker == NULL)
   282:           {
   283:             fprintf(stderr,"Unable to initialise async I/O system: terminating\n");
   284:             exit(1);
   285:           }
   286:           async = (*ptr_create_async_hooker)(
   287:             20000, // bound on resumable thread queue
   288:             50,    // bound on general input job queue
   289:             2,     // number of threads in job pool
   290:             50,    // bound on async fileio job queue
   291:             1      // number of threads doing async fileio
   292:           );
   293:         }
   294:         ++async_count;
   295:         void *dreq =  (((_ref_*)(ss.request->data))->get_data());
   296: 
   297:         // requests are now ALWAYS considered asynchronous
   298:         // even if the request handler reschedules them immediately
   299:         async->handle_request(dreq, ss.ft);
   300:         ss.pc = next_fthread_pos;
   301:       }
   302:       goto process_active;
   303: 
   304:       default:
   305:         fprintf(stderr,"Unknown service request code 0x%4x\n",ss.request->variant);
   306:         abort();
   307:     }
   308:     fprintf(stderr,"Unknown frun return status 0x%4x\n",ss.fs);
   309:     abort();
   310: 
   311:   do_async:
   312:     // ran out of active threads - are there any in the async queue?
   313:     if(debug_driver){
   314:       fprintf(stderr, "out of active synchronous threads, trying async, count=%ld\n",async_count);
   315:     }
   316: 
   317:     if(async && async_count > 0){
   318:       // STILL A ROOT
   319:       fthread_t* ftp = async->dequeue();
   320:       if(debug_driver)
   321:         fprintf(stderr,"Async Retrieving fthread %p\n",ftp);
   322:       active->push_front(ftp);
   323:       --async_count;
   324:       ss.pc = next_fthread_pos;
   325:       goto process_active;
   326:     }
   327: 
   328:     if(debug_driver)fprintf(stderr,"Out of jobs\n");
   329:   cleanup:;
   330:   }
   331:   catch (flx_exception_t &x) { flx_exception_handler (&x); }
   332:   catch (std::exception &x) { std_exception_handler (&x); }
   333:   catch (...) { fprintf(stderr,"Unknown exception in thread!\n"); }
   334: 
   335:   try
   336:   {
   337:     if(debug_driver)fprintf(stderr,"Terminating Felix subsystem\n");
   338:     delete async;
   339:     delete active;
   340:   }
   341:   catch (...) { fprintf(stderr,"Unknown exception deleting async!\n"); }
   342: 
   343:   // if this fails the whole system is corrupted
   344:   thread_control->remove_thread();
   345: }
   346: 
   347: // RUN A FELIX INSTANCE IN THE CURRENT PTHREAD
   348: //
   349: // CURRENTLY ONLY CALLED ONCE IN MAIN THREAD
   350: 
   351: int run_felix_pthread(
   352:   bool debug_driver,
   353:   gc_profile_t *gcp,
   354:   flx_dynlink_t *library,
   355:   flx_libinit_t *instance
   356: )
   357: {
   358:    flx::gc::generic::collector_t *collector = gcp->collector;
   359:    std::list<fthread_t*> *active =new std::list<fthread_t*>;
   360: 
   361:   fthread_t *flx_main = NULL;
   362:   {
   363:     con_t *top = instance->main_proc;
   364:     if(top)
   365:     {
   366:       flx_main = new (*collector,_fthread_ptr_map) fthread_t(top);
   367:       collector->add_root(flx_main);
   368:       active->push_front(flx_main);
   369:     }
   370:   }
   371: 
   372:   {
   373:     con_t *top = instance->start_proc;
   374:     fthread_t *ft = new (*collector,_fthread_ptr_map) fthread_t(top);
   375:     collector->add_root(ft);
   376:     active->push_front(ft);
   377:   }
   378: 
   379:   {
   380:     thread_control_t thread_control;
   381:     thread_control.add_thread();
   382: 
   383:     doflx(new doflx_data(debug_driver, gcp, active, &thread_control)); // deletes active for us!
   384: 
   385:     if(debug_driver)fprintf(stderr,"MAIN THREAD FINISHED: waiting for other threads\n");
   386:     thread_control.join_all();
   387:     if(debug_driver)fprintf(stderr,"ALL THREADS DEAD: mainline cleanup!\n");
   388: 
   389:     if(debug_driver){
   390:       unsigned long uncollected = collector->get_allocation_count();
   391:       unsigned long roots = collector->get_root_count();
   392:       fprintf(stderr,
   393:         "program finished, %ld collections, %ld uncollected objects, roots %ld\n",
   394:         gcp->collections,uncollected,roots);
   395:     }
   396:   }
   397: 
   398:   if(gcp->finalise)
   399:     do_final_cleanup(debug_driver, gcp, library, instance);
   400:   return 0;
   401: }
   402: 
   403: // terminates process!
   404: // Not called by default (let the OS clean up)
   405: //
   406: // NEEDS TO BE SPLIT UP so that destroying
   407: // a program instance is separated from unloading
   408: // the library
   409: 
   410: int do_final_cleanup(
   411:   bool debug_driver,
   412:   gc_profile_t *gcp,
   413:   flx_dynlink_t *library,
   414:   flx_libinit_t *instance
   415: )
   416: {
   417:   flx::gc::generic::collector_t *collector = gcp->collector;
   418: 
   419:   // garbage collect application objects
   420:   {
   421:     if(debug_driver || gcp->debug_collections)
   422:       fprintf(stderr,"Finalisation: pass 1 Data collection starts ..\n");
   423:     unsigned long n = collector->collect();
   424:     unsigned long a = collector->get_allocation_count();
   425:     if(debug_driver || gcp->debug_collections)
   426:       fprintf(stderr,"flx_run collected %ld objects, %ld left\n",n,a);
   427:   }
   428: 
   429:   // Destroy program instance/ thread frame object
   430: 
   431:   if(debug_driver)
   432:     fprintf(stderr,"Destroying program instance\n");
   433:   instance->destroy();
   434: 
   435:   // garbage collect system objects
   436: 
   437:   {
   438:     if(debug_driver || gcp->debug_collections)
   439:       fprintf(stderr,"Finalisation: pass 2 Final collection starts ..\n");
   440:     unsigned long n = collector->collect();
   441:     unsigned long a = collector->get_allocation_count();
   442:     if(debug_driver || gcp->debug_collections)
   443:       fprintf(stderr,"Collected %ld objects, %ld left (should be 0)\n",n,a);
   444:     if(a!=0){
   445:       fprintf(stderr,"flx_run %ld uncollected objects, should be zero!!\n",a);
   446:       return 5;
   447:     }
   448:   }
   449: 
   450:   // dump the DLL
   451: 
   452:   if(debug_driver)
   453:     fprintf(stderr,"Libref cnt = %ld\n",library->refcnt);
   454:   if(library->refcnt >0)
   455:   {
   456:     if(debug_driver)
   457:       fprintf(stderr,"flx_run %p library still referenced %ld times\n",
   458:         library->library,library->refcnt
   459:       );
   460:   }
   461:   if(debug_driver)
   462:     fprintf(stderr,"Unlinking library ..\n");
   463:   library->unlink();
   464:   return 0;
   465: }
   466: 
   467: // MAINLINE, ONLY DONE ONCE
   468: int run_felix(
   469:   bool debug_driver,
   470:   gc_profile_t *gcp,
   471:   char *filename,
   472:   int flx_argc,
   473:   char **flx_argv
   474: )
   475: {
   476:   try
   477:   {
   478:     if(debug_driver)
   479:       fprintf(stderr,"flx_run driver begins %s\n",flx_argv[0]);
   480:     flx_dynlink_t library;
   481:     flx_libinit_t instance;
   482:     library.link(filename);
   483: 
   484:     flx::gc::generic::collector_t *collector = gcp->collector;
   485: 
   486:     instance.create(&library, collector,library.main_sym,flx_argc,flx_argv,stdin,stdout,stderr);
   487: 
   488:     if(debug_driver){
   489:       fprintf(stderr,"loaded library %s at %p\n",filename,library.library);
   490:       fprintf(stderr,"thread frame at %p\n",instance.thread_frame);
   491:       fprintf(stderr,"initial continuation at %p\n",instance.start_proc);
   492:       fprintf(stderr,"main continuation at %p\n",instance.main_proc);
   493:     }
   494:     run_felix_pthread(debug_driver,gcp,&library,&instance);
   495: 
   496:     if(gcp->finalise)
   497:     {
   498:       if(library.refcnt >0)
   499:       {
   500:         fprintf(stderr,"flx_run %p library still referenced %ld times?!\n",library.library,library.refcnt);
   501:         return 6;
   502:       }
   503:       if(debug_driver)
   504:         fprintf(stderr,"flx_run driver ends with finalisation complete\n");
   505:     }
   506:     else
   507:     {
   508:       if(debug_driver || gcp->debug_collections)
   509:       {
   510:         unsigned long a = collector->get_allocation_count();
   511:         fprintf(stderr,"flx_run driver ends with finalisation skipped, %ld uncollected objects\n",a);
   512:       }
   513:     }
   514:   }
   515:   catch (flx_exception_t &x)
   516:   {
   517:     return flx_exception_handler(&x);
   518:   }
   519:   catch (...)
   520:   {
   521:     fprintf(stderr,"flx_run driver ends with unknown EXCEPTION\n");
   522:     return 4;
   523:   }
   524:   return 0;
   525: }
   526: 
   527: int main(int argc, char** argv)
   528: {
   529:   int error_exit_code = 0;
   530: #ifndef FLX_STATIC_LINK
   531:   bool static_link = false;
   532:   if (argc<2)
   533:   {
   534:     printf("usage: flx_run [--debug] dll_filename options ..\n");
   535:     printf("  environment variables:\n");
   536:     printf("  FLX_DEBUG               # enable debugging traces (default off)\n");
   537:     printf("  FLX_DEBUG_ALLOCATIONS   # enable debugging allocator (default FLX_DEBUG)\n");
   538:     printf("  FLX_DEBUG_COLLECTIONS   # enable debugging collector (default FLX_DEBUG)\n");
   539:     printf("  FLX_DEBUG_DRIVER        # enable debugging driver (default FLX_DEBUG)\n");
   540:     printf("  FLX_FINALISE            # whether to cleanup on termination (default NO)\n");
   541:     printf("  FLX_COMPACT=n           # size of compaction arena, 0 to disable (default)\n");
   542:     printf("  FLX_GC_FREQ=n           # how often to call garbage collector (default 1000)\n");
   543:     return 1;
   544:   }
   545:   char *filename = argv[1];
   546:   char **flx_argv = argv+1;
   547:   int flx_argc = argc-1;
   548:   bool debug = (argc > 1) && (strcmp(argv[1],"--debug")==0);
   549:   if(debug)
   550:   {
   551:     if(argc<3)
   552:     {
   553:       printf("usage: flx_run [--debug] dll_filename options ..\n");
   554:       return 1;
   555:     }
   556:     filename = argv[2];
   557:     --flx_argc;
   558:     ++flx_argv;
   559:   }
   560: #else
   561:   bool static_link = true;
   562:   char *filename = argv[0];
   563:   char **flx_argv = argv;
   564:   int flx_argc = argc;
   565:   bool debug = false;
   566: 
   567: //  printf("Statically linked Felix program running\n");
   568: #endif
   569:   char *debug_env = std::getenv("FLX_DEBUG");
   570:   debug = debug || debug_env != 0;
   571:   if(debug)
   572:   {
   573:     fprintf(stderr,"[FLX_DEBUG] Debug enabled for %s link program\n",static_link?"static":"dynamic");
   574:   }
   575: 
   576:   bool debug_allocations = debug || std::getenv("FLX_DEBUG_ALLOCATIONS") !=0;
   577:   if(debug_allocations)
   578:   {
   579:     fprintf(stderr,"[FLX_DEBUG_ALLOCATIONS] Allocation debug enabled\n");
   580:   }
   581: 
   582:   bool debug_collections = debug || std::getenv("FLX_DEBUG_COLLECTIONS") !=0;
   583:   if(debug_collections)
   584:   {
   585:     fprintf(stderr,"[FLX_DEBUG_COLLECTIONS] Collection debug enabled\n");
   586:   }
   587: 
   588: 
   589:   bool debug_driver = debug || std::getenv("FLX_DEBUG_DRIVER") !=0;
   590:   if(debug_driver)
   591:   {
   592:     fprintf(stderr,"[FLX_DEBUG_DRIVER] Driver debug enabled\n");
   593:   }
   594: 
   595: 
   596:   char *finalise_env= std::getenv("FLX_FINALISE");
   597:   bool finalise = finalise_env != 0;
   598: 
   599:   if(debug)
   600:     fprintf(stderr,"[FLX_FINALISE] Finalisation %s\n",finalise? "Enabled" : "Disabled");
   601: 
   602:   char *compact_env= std::getenv("FLX_COMPACT");
   603:   unsigned long compact = compact_env?atol(compact_env):0;
   604:   if(debug)
   605:   {
   606:     if(compact)
   607:       fprintf(stderr,"[FLX_COMPACT] Compacting with arena minimum size = %ldK\n",compact);
   608:     else
   609:       fprintf(stderr,"[FLX_COMPACT] Compaction initially OFF\n");
   610:   }
   611:   compact = compact * 1024;
   612: 
   613:   char *gc_freq_env= std::getenv("FLX_GC_FREQ");
   614:   unsigned long gc_freq = gc_freq_env?atol(gc_freq_env):1000;
   615:   if (gc_freq < 1) gc_freq = 1;
   616:   if(debug)
   617:     fprintf(stderr,"[FLX_GC_FREQ] call gc every %lu iterations\n",gc_freq);
   618: 
   619: #if FLX_HAVE_GNU
   620:     if(debug)fprintf(stderr, "Compiled by g++\n");
   621:     static void *init_sp = sp;
   622:     static void *init_fframe FLX_UNUSED = __builtin_frame_address(0);
   623:     static void *init_ret = __builtin_return_address(0);
   624:     if(debug)fprintf(stderr, "Stack pointer = %p, frame=%p, return=%p\n",sp,init_fframe,init_ret);
   625: #endif
   626:   if(debug)
   627:     for(int i=0; i<flx_argc; ++i)
   628:     fprintf(stderr,"flx_argv[%d]->%s\n",i,flx_argv[i]);
   629: 
   630:   flx::gc::generic::allocator_t *allocator =
   631:     new flx::gc::collector::malloc_free()
   632:   ;
   633:   allocator->set_debug(debug_allocations);
   634: 
   635:   flx::gc::collector::flx_collector_t *collector =
   636:     new flx::gc::collector::flx_ts_collector_t(allocator)
   637:   ;
   638:   collector->set_debug(debug_collections);
   639:   if(compact)
   640:   {
   641:     collector->set_min_arena_size(compact);
   642:     collector->compact(false);
   643:   }
   644: 
   645: 
   646:   gc_profile_t *gcp = new gc_profile_t(
   647:     debug_allocations,
   648:     debug_collections,
   649:     compact,
   650:     gc_freq,
   651:     finalise,
   652:     collector
   653:   );
   654:   error_exit_code = run_felix(
   655:     debug_driver,
   656:     gcp,
   657:     filename,flx_argc,flx_argv
   658:   );
   659: 
   660:   delete gcp;
   661:   delete collector;
   662:   delete allocator;
   663: 
   664: #if FLX_HAVE_GNU
   665:     // check the frame pointer isn't corrupted
   666:     static void *fin_sp = sp;
   667:     static void *fin_fframe FLX_UNUSED = __builtin_frame_address(0);
   668:     static void *fin_ret = __builtin_return_address(0);
   669:     if (init_sp != fin_sp ) {
   670:       fprintf(stderr,"g++: STACK POINTER ERROR %p != %p\n",init_sp,fin_sp);
   671:     }
   672: // I have to comment this out, because it only applies if the
   673: // gcc compiler is using the frame pointer.. it doesn't if you
   674: // say -fomit-frame-pointer, for example .. I don't know if there
   675: // is a way to tell inside the code ..
   676: #if 0
   677:     if (init_fframe != fin_fframe) {
   678:       fprintf(stderr,"g++: FRAME POINTER ERROR %p != %p\n",init_fframe,fin_fframe);
   679:     }
   680: #endif
   681:     else if (init_ret != fin_ret) {
   682:       fprintf(stderr,"g++: RETURN ADDRESS ERROR %p != %p\n",init_ret,fin_ret);
   683:     }
   684: #endif
   685:   if(debug)fprintf(stderr,"flx_run driver ends code=%d\n",error_exit_code);
   686:   return error_exit_code;
   687: }
End cpp section to rtl/flx_run.include[1]
Start cpp section to rtl/flx_run.cxx[1 /1 ]
     1: #line 3259 "./lpsrc/flx_rtl.pak"
     2: #define FLX_SUPPORT_ASYNC 0
     3: 
     4: #include "flx_run.include"
End cpp section to rtl/flx_run.cxx[1]
Start cpp section to rtl/flx_arun.cxx[1 /1 ]
     1: #line 3265 "./lpsrc/flx_rtl.pak"
     2: #define FLX_SUPPORT_ASYNC 1
     3: 
     4: #include "flx_run.include"
End cpp section to rtl/flx_arun.cxx[1]
Start cpp section to rtl/flx_main.cpp[1 /1 ]
     1: #line 3271 "./lpsrc/flx_rtl.pak"
     2: #include "flx_rtl_config.hpp"
     3: #include "flx_rtl.hpp"
     4: // THIS IS A DO NOTHING MAINLINE FOR USE WHEN STATICALLY LINKING
     5: extern "C" flx::rtl::con_t *flx_main( void *p){ return 0; }
End cpp section to rtl/flx_main.cpp[1]
Start cpp section to test/drivers/mickey_mouse.cxx[1 /1 ]
     1: #line 3278 "./lpsrc/flx_rtl.pak"
     2: #include <stdio.h>
     3: #include "flx_rtl.hpp"
     4: #include "flx_collector.hpp"
     5: #include "flx_dynlink.hpp"
     6: 
     7: using namespace std;
     8: using namespace flx;
     9: 
    10: int main(int argc, char** argv)
    11: {
    12:   rtl::flx_dynlink_t library;
    13:   rtl::flx_libinit_t instance;
    14:   library.link(argc>1?argv[1]:"<static>");
    15:   gc::collector::malloc_free allocator;
    16:   gc::collector::flx_collector_t collector(&allocator);
    17:   instance.create(&library, &collector,library.main_sym,argc,argv,stdin,stdout,stderr);
    18:   rtl::con_t *top = instance.start_proc;
    19:   while( top ) top = top->resume();
    20:   return 0;
    21: }
End cpp section to test/drivers/mickey_mouse.cxx[1]
Start cpp section to rtl/flx_i18n.hpp[1 /1 ]
     1: #line 3301 "./lpsrc/flx_rtl.pak"
     2: #ifndef __FLX_I18N_H__
     3: #define __FLX_I18N_H__
     4: #include <string>
     5: #include "flx_rtl_config.hpp"
     6: 
     7: namespace flx { namespace rtl { namespace i18n {
     8:    RTL_EXTERN std::string utf8(unsigned long);
     9: }}}
    10: #endif
End cpp section to rtl/flx_i18n.hpp[1]
Start cpp section to rtl/flx_i18n.cpp[1 /1 ]
     1: #line 3313 "./lpsrc/flx_rtl.pak"
     2: #include "flx_i18n.hpp"
     3: namespace flx { namespace rtl { namespace i18n {
     4:   std::string utf8(unsigned long i)
     5:   {
     6:     char s[6];
     7:     if (i < 0x80UL )
     8:     {
     9:       s[0]= i;
    10:       s[1]= 0;
    11:     }
    12:     else if (i < 0x800UL )
    13:     {
    14:       s[0]=0xC0u | (i >> 6ul)  & 0x1Fu;
    15:       s[1]=0x80u | i           & 0x3Fu;
    16:       s[2]=0;
    17:     }
    18:     else if (i < 0x10000UL )
    19:     {
    20:       s[0]=0xE0u | (i >> 12ul) & 0xFu;
    21:       s[1]=0x80u | (i >> 6ul)  & 0x3Fu;
    22:       s[2]=0x80u | i           & 0x3F;
    23:       s[3]=0;
    24:     }
    25:     else if (i < 0x200000UL )
    26:     {
    27:       s[0]=0xF0u | (i >> 18ul) & 0x7u;
    28:       s[1]=0x80u | (i >> 12ul) & 0x3Fu;
    29:       s[2]=0x80u | (i >> 6ul)  & 0x3Fu;
    30:       s[3]=0x80u | i           & 0x3F;
    31:       s[4]=0;
    32:     }
    33:     else if (i < 0x4000000UL )
    34:     {
    35:       s[0]=0xF8u | (i >> 24ul) & 0x3u;
    36:       s[1]=0x80u | (i >> 18ul) & 0x3Fu;
    37:       s[2]=0x80u | (i >> 12ul) & 0x3Fu;
    38:       s[3]=0x80u | (i >> 6ul)  & 0x3Fu;
    39:       s[4]=0x80u | i           & 0x3Fu;
    40:       s[5]=0;
    41:     }
    42:     else
    43:     {
    44:       s[0]=0xFCu | (i >> 30ul) & 0x1u;
    45:       s[1]=0x80u | (i >> 24ul) & 0x3Fu;
    46:       s[2]=0x80u | (i >> 18ul) & 0x3Fu;
    47:       s[3]=0x80u | (i >> 12ul) & 0x3Fu;
    48:       s[4]=0x80u | (i >> 6ul)  & 0x3Fu;
    49:       s[5]=0x80u | i           & 0x3Fu;
    50:       s[6]=0;
    51:     }
    52:     return s;
    53:   }
    54: }}}
End cpp section to rtl/flx_i18n.cpp[1]
Start cpp section to rtl/flx_ioutil.hpp[1 /1 ]
     1: #line 3369 "./lpsrc/flx_rtl.pak"
     2: #ifndef FLX_IOUTIL
     3: #define FLX_IOUTIL
     4: #include <string>
     5: #include <cstdio>
     6: #include "flx_rtl_config.hpp"
     7: 
     8: namespace flx { namespace rtl { namespace ioutil {
     9:   RTL_EXTERN std::string load_file (std::FILE *);
    10:   RTL_EXTERN std::string load_file (std::string);
    11:   RTL_EXTERN std::string readln(std::FILE*);
    12:   RTL_EXTERN void write (std::FILE *, std::string);
    13:   RTL_EXTERN void writeln (std::FILE *, std::string);
    14: }}}
    15: #endif
End cpp section to rtl/flx_ioutil.hpp[1]
Start cpp section to rtl/flx_ioutil.cpp[1 /1 ]
     1: #line 3386 "./lpsrc/flx_rtl.pak"
     2: #include <cstdio>
     3: #include <cstring>
     4: #include <string>
     5: #include "flx_ioutil.hpp"
     6: namespace flx { namespace rtl { namespace ioutil {
     7:   using namespace std;
     8: 
     9:   string load_file (FILE *fi)
    10:   {
    11:     if (fi)
    12:     {
    13:       string x = "";
    14:       char buffer[512];
    15:       while (fgets(buffer,512,fi))
    16:         x = x + string(buffer);
    17:       fclose(fi);
    18:       return x;
    19:     }
    20:     else return "";
    21:   }
    22: 
    23:   string load_file (string f)
    24:   {
    25:     char const *fname = f.data();
    26:     FILE *fi = fopen(fname,"rt");
    27:     if (fi)
    28:     {
    29:       string x = "";
    30:       char buffer[512];
    31:       while (fgets(buffer,512,fi))
    32:         x = x + string(buffer);
    33:       fclose(fi);
    34:       return x;
    35:     }
    36:     else return "";
    37:   }
    38: 
    39:   // includes newline if present
    40:   // null string indicates end of file
    41:   string readln (FILE *fi)
    42:   {
    43:     if(fi)
    44:     {
    45:       string x = "";
    46:       char buffer[513];
    47:       buffer[512]='\0';
    48:       int n;
    49:       while
    50:       (
    51:         !(
    52:           (n=x.size()) &&
    53:           x[n-1]=='\n'
    54:         )
    55:         &&
    56:         fgets(buffer,512,fi)
    57:       )
    58:         x = x + string(buffer);
    59:       return x;
    60:     }
    61:     else return "";
    62:   }
    63: 
    64:   void write (FILE *fi, string s)
    65:   {
    66:     fwrite(s.data(),s.size(),1,fi);
    67:   }
    68: 
    69:   void writeln (FILE *fi, string s)
    70:   {
    71:     static char *eol = "\n";
    72:     static int n = 0;
    73:     if(n==0)n=strlen(eol);
    74:     fwrite(s.data(),s.size(),1,fi);
    75:     fwrite(eol,n,1,fi);
    76:   }
    77: 
    78: }}}
End cpp section to rtl/flx_ioutil.cpp[1]
Start cpp section to rtl/flx_strutil.hpp[1 /1 ]
     1: #line 3466 "./lpsrc/flx_rtl.pak"
     2: #include <string>
     3: #include <sstream>
     4: #include <stdarg.h>
     5: 
     6: #include "flx_rtl_config.hpp"
     7: 
     8: //RF: was only to commented out to fix macosx problem,
     9: //but lets see what happens to all the other builds.
    10: //#ifndef MACOSX
    11: //template class RTL_EXTERN std::basic_string<char>;
    12: //#endif
    13: 
    14: namespace flx { namespace rtl { namespace strutil {
    15:   using namespace std;
    16:   template<class T>
    17:   basic_string<T> mul(basic_string<T> s, int n) {
    18:     basic_string<T> r = "";
    19:     while(n--) r+=s;
    20:     return r;
    21:   }
    22: 
    23:   // normalise string positions Python style
    24:   // note substr requires 0<=b<=size, 0<=n,
    25:   // however n>size is OK
    26:   template<class T>
    27:   basic_string<T> substr(basic_string<T> const &s, int b, int e)
    28:   {
    29:     int n = s.size();
    30:     if(b<0)  b=b+n;
    31:     if(b<0)  b=0;
    32:     if(b>=n) b=n;
    33:     if(e<0)  e=e+n;
    34:     if(e<0)  e=0;
    35:     if(e>=n) e=n;
    36:     int m =  e-b;
    37:     if(m<0)  m=0;
    38:     return s.substr(b,m);
    39:   }
    40: 
    41:   template<class T>
    42:   T subscript(basic_string<T> const &s, int i)
    43:   {
    44:     int n = s.size();
    45:     if(i<0)  i=i+n;
    46:     return i<0 || i >= n ? T(0) : s[i];
    47:   }
    48: 
    49:   template<class T>
    50:   string str(T const &t) {
    51:     std::ostringstream x;
    52:     x << t;
    53:     return x.str();
    54:   }
    55: 
    56:   RTL_EXTERN string atostr(char const *a);
    57:   RTL_EXTERN string flx_asprintf(char *fmt,...);
    58: 
    59: }}}
End cpp section to rtl/flx_strutil.hpp[1]
Start cpp section to rtl/flx_strutil.cpp[1 /1 ]
     1: #line 3527 "./lpsrc/flx_rtl.pak"
     2: #include <cstdlib>
     3: #include "flx_strutil.hpp"
     4: 
     5: namespace flx { namespace rtl { namespace strutil {
     6: 
     7:   string atostr(char const *a) {
     8:     if(a) return a;
     9:     else return "";
    10:   }
    11: 
    12: #ifdef HAVE_VSNPRINTF
    13:   string flx_asprintf(char *fmt,...){
    14:     va_list ap;
    15:     va_start(ap,fmt);
    16:     int n = vsnprintf(NULL,0,fmt,ap);
    17:     va_end(ap);
    18:     char *res = (char*)malloc(n+1);
    19:     va_start(ap,fmt);
    20:     vsnprintf(res,n+1,fmt,ap);
    21:     va_end(ap);
    22:     string s = string(res);
    23:     free(res);
    24:     return s;
    25:   }
    26: #else
    27:   // THIS IS UNSAFE .. but Windows sucks.
    28:   // It documents vsnprintf .. but doesn't provide it
    29:   string flx_asprintf(char *fmt,...){
    30:     va_list ap;
    31:     int n = 1000;
    32:     char *res = (char*)malloc(n+1);
    33:     va_start(ap,fmt);
    34:     vsprintf(res,fmt,ap);
    35:     va_end(ap);
    36:     string s = string(res);
    37:     free(res);
    38:     return s;
    39:   }
    40: #endif
    41: 
    42: }}}
End cpp section to rtl/flx_strutil.cpp[1]
Start cpp section to rtl/flx_executil.hpp[1 /1 ]
     1: #line 3572 "./lpsrc/flx_rtl.pak"
     2: #ifndef FLX_EXECUTIL
     3: #define FLX_EXECUTIL
     4: #include "flx_rtl_config.hpp"
     5: #include "flx_rtl.hpp"
     6: 
     7: namespace flx { namespace rtl { namespace executil {
     8:   RTL_EXTERN void run(flx::rtl::con_t *c);
     9: }}}
    10: #endif
End cpp section to rtl/flx_executil.hpp[1]
Start cpp section to rtl/flx_executil.cpp[1 /1 ]
     1: #line 3584 "./lpsrc/flx_rtl.pak"
     2: #include "flx_executil.hpp"
     3: namespace flx { namespace rtl { namespace executil {
     4: void run(flx::rtl::con_t *p)
     5: {
     6:   while(p)
     7:   {
     8:     try { p=p->resume(); }
     9:     catch (flx::rtl::con_t *x) { p = x; }
    10:   }
    11: }
    12: 
    13: }}}
    14: 
End cpp section to rtl/flx_executil.cpp[1]