/* create and schedule a new lua process */ static int luaproc_create_newproc( lua_State *L ) { size_t len; luaproc *lp; luaL_Buffer buff; const char *code; int d; int lt = lua_type( L, 1 ); /* check function argument type - must be function or string; in case it is a function, dump it into a binary string */ if ( lt == LUA_TFUNCTION ) { lua_settop( L, 1 ); luaL_buffinit( L, &buff ); d = dump( L, luaproc_buff_writer, &buff, FALSE ); if ( d != 0 ) { lua_pushnil( L ); lua_pushfstring( L, "error %d dumping function to binary string", d ); return 2; } luaL_pushresult( &buff ); lua_insert( L, 1 ); } else if ( lt != LUA_TSTRING ) { lua_pushnil( L ); lua_pushfstring( L, "cannot use '%s' to create a new process", luaL_typename( L, 1 )); return 2; } /* get pointer to code string */ code = lua_tolstring( L, 1, &len ); /* get exclusive access to recycled lua processes list */ pthread_mutex_lock( &mutex_recycle_list ); /* check if a lua process can be recycled */ if ( recyclemax > 0 ) { lp = list_remove( &recycle_list ); /* otherwise create a new lua process */ if ( lp == NULL ) { lp = luaproc_new( L ); } } else { lp = luaproc_new( L ); } /* release exclusive access to recycled lua processes list */ pthread_mutex_unlock( &mutex_recycle_list ); /* init lua process */ lp->status = LUAPROC_STATUS_IDLE; lp->args = 0; lp->chan = NULL; /* load code in lua process */ luaproc_loadbuffer( L, lp, code, len ); /* if lua process is being created from a function, copy its upvalues and remove dumped binary string from stack */ if ( lt == LUA_TFUNCTION ) { if ( luaproc_copyupvalues( L, lp->lstate, 2 ) == FALSE ) { luaproc_recycle_insert( lp ); return 2; } lua_pop( L, 1 ); } sched_inc_lpcount(); /* increase active lua process count */ sched_queue_proc( lp ); /* schedule lua process for execution */ lua_pushboolean( L, TRUE ); return 1; }
/* worker thread main function */ void *workermain( void *args ) { luaproc *lp; int procstat; /* main worker loop */ while ( TRUE ) { /* wait until instructed to wake up (because there's work to do or because workers must be destroyed) */ pthread_mutex_lock( &mutex_sched ); while (( list_count( &ready_lp_list ) == 0 ) && ( destroyworkers <= 0 )) { pthread_cond_wait( &cond_wakeup_worker, &mutex_sched ); } if ( destroyworkers > 0 ) { /* check whether workers should be destroyed */ destroyworkers--; /* decrease workers to be destroyed count */ workerscount--; /* decrease active workers count */ /* remove worker from workers table */ lua_getglobal( workerls, LUAPROC_SCHED_WORKERS_TABLE ); lua_pushlightuserdata( workerls, (void *)pthread_self( )); lua_pushnil( workerls ); lua_rawset( workerls, -3 ); lua_pop( workerls, 1 ); pthread_cond_signal( &cond_wakeup_worker ); /* wake other workers up */ pthread_mutex_unlock( &mutex_sched ); pthread_exit( NULL ); /* destroy itself */ } /* remove lua process from the ready queue */ lp = list_remove( &ready_lp_list ); pthread_mutex_unlock( &mutex_sched ); /* execute the lua code specified in the lua process struct */ procstat = luaproc_resume( luaproc_get_state( lp ), NULL, luaproc_get_numargs( lp )); /* reset the process argument count */ luaproc_set_numargs( lp, 0 ); /* has the lua process sucessfully finished its execution? */ if ( procstat == 0 ) { luaproc_set_status( lp, LUAPROC_STATUS_FINISHED ); luaproc_recycle_insert( lp ); /* try to recycle finished lua process */ sched_dec_lpcount(); /* decrease active lua process count */ } /* has the lua process yielded? */ else if ( procstat == LUA_YIELD ) { /* yield attempting to send a message */ if ( luaproc_get_status( lp ) == LUAPROC_STATUS_BLOCKED_SEND ) { luaproc_queue_sender( lp ); /* queue lua process on channel */ /* unlock channel */ luaproc_unlock_channel( luaproc_get_channel( lp )); } /* yield attempting to receive a message */ else if ( luaproc_get_status( lp ) == LUAPROC_STATUS_BLOCKED_RECV ) { luaproc_queue_receiver( lp ); /* queue lua process on channel */ /* unlock channel */ luaproc_unlock_channel( luaproc_get_channel( lp )); } /* yield on explicit coroutine.yield call */ else { /* re-insert the job at the end of the ready process queue */ pthread_mutex_lock( &mutex_sched ); list_insert( &ready_lp_list, lp ); pthread_mutex_unlock( &mutex_sched ); } } /* or was there an error executing the lua process? */ else { /* print error message */ fprintf( stderr, "close lua_State (error: %s)\n", luaL_checkstring( luaproc_get_state( lp ), -1 )); lua_close( luaproc_get_state( lp )); /* close lua state */ sched_dec_lpcount(); /* decrease active lua process count */ } } }