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