contents   index   previous   next



GLOBAL MANIPULATION

 

Although the intent of fibers is to conserve memory by sharing overhead, often each fiber should still be independent. For instance, you may not want them to share global variables. This is easy to accomplish. After you create the initial context and set up the libraries in it using seCreateContext, you preserve that global object. Then for each fiber (including the original context returned by seCreateContext), you give it a new global object with its _prototype pointing to the preserved global object. Thus, all new variables created in a fiber will be created in its private global object, yet it still can refer via the global’s prototype to the original global object which contains all the standard function libraries.

 

Here is a short example ScriptEase API application that creates several fibers and runs them all.

 

#define MAX_FIBERS 5

 

 

/* ---------------------------------------------------------

 * Error handler

 * --------------------------------------------------------- */

 

   SE_CALLBACK( void )

my_error_printer(secontext se,seconstcharptr text)

{

   printf_sechar(UNISTR("Error encountered: %s\n"),text);

}

 

/* A wrapper function to write out a string. It converts

 * whatever argument it is given to a string then writes it

 * to the terminal using 'printf'. The user would use it like    

 * this:

 *

 *    StringOut("Hello, world!");

 */

 

 

/* ---------------------------------------------------------

 * Text output

 * --------------------------------------------------------- */

 

   SE_CALLBACK( void )

StringOut(secontext se,sememcount argc)

{

   sememcount i;

   seconstcharptr text;

 

   for( i=0;i<argc;i++ )

   {

      /* Get each successive argument and print them

       */

      text = seGetString(se, SE_ARGS,SE_NUM(i), NULL);

      printf_sechar(UNISTR("%s\n"),text);

   }

}

 

SE_BEGIN_LIB_TABLE( SampleFunctionList )

   SE_FUNCTION( "StringOut",    StringOut,      1, -1,  

                SE_SECURE, SE_DONTENUM ),

SE_END_LIB_TABLE

 

 

   void

add_fiber(secontext se,secontext *table,int *number,

          seobject glob)

{

   assert( (*number)<MAX_FIBERS );

   table[(*number)++] = se;

 

   /* give the fiber a private global */

   sePutObject(se,SE_GLOBAL,SE_VALUE,seMakeObject(se));

   /* but point back to shared so can see it */

   sePutObject(se,SE_GLOBAL,SE_STOCK(_prototype),glob);

 

   seEval(se,UNISTR("var a = 10;\nStringOut(a);\n"),SE_TEXT,

          NULL,NULL,SE_START,NULL);

}

 

   void

remove_fiber(int num,secontext *table,int *number)

{

   assert( num<(*number) );

 

   /* we are done with the context */

   seDestroyContext(table[num]);

 

   /* remove it from the table */

   while( num<(*number)-1 )

   {

      table[num] = table[num+1];

      num++;

   }

   (*number)--;

}

 

   void

main(int argc,char **argv)

{

   secontext se;

   secontext fibers[MAX_FIBERS];

   int fibers_used = 0;

   int fiber_current = 0;

   seobject shared_global;

   struct seContextParams params;

 

 

   seInitialize();

 

   memset(&params,0,sizeof(params));

 

   /* the print error function is the one required function. */

   params.sePrintErrorFunc = my_error_printer;

   

   /* initialize the main context */

   se = seCreateContext(&params,MY_JSE_USER_KEY);

   if( se==NULL )

   {

      printf_sechar(UNISTR("Invalid user key.\n"));

      exit(0);

   }

 

   shared_global = seGetObject(se,SE_GLOBAL,SE_VALUE);

 

   /* add libaries so we have the StringOut function */

   seAddLibTable(se,SampleFunctionList,NULL);

 

 

   /* Add the original context to our fiber list. All contexts

    * including the parent will be treated identically

    */

   add_fiber(se,fibers,&fibers_used,shared_global);

 

 

   /* Create some more fibers. All are added to one big

    * pool.

    */

   while( fibers_used<MAX_FIBERS )

      add_fiber(seCreateFiber(fibers[0]),fibers,

                &fibers_used,shared_global);

 

 

   /* run the fibers until all have exited. For each fiber,

    * execute its next available statement using seExec().

    * Notice that an seEval using SE_START was started in

    * each fiber when it was added above. As each fiber 

    * finishes its seEval(), we remove it from the fiber list.

    * We exit when all fibers are done.

    */

   while( fibers_used>0 )

   {

      if( !seExec(fibers[fiber_current]) )

      {

         remove_fiber(fiber_current,fibers,&fibers_used);

         /* and continue using the fiber that fell into its

          * place

          */

      }

      else

      {

         fiber_current++;

      }

      if( fiber_current>=fibers_used ) fiber_current = 0;

   }

 

 

   /* Done with the sample, shut everything down. */

   seTerminate();

}


YIELDING AND SUSPENDING