int DaoObject_InvokeMethod( DaoObject *self, DaoObject *othis, DaoProcess *proc, DString *name, DaoValue *P[], int N, int ignore_return, int execute ) { DaoValue *V = NULL; DaoValue *O = (DaoValue*)self; int errcode = DaoObject_GetData( self, name, &V, othis ); if( errcode ) return errcode; if( V == NULL || V->type != DAO_ROUTINE ) return DAO_ERROR_TYPE; if( DaoProcess_PushCallable( proc, (DaoRoutine*) V, O, P, N ) ) goto InvalidParam; if( ignore_return ) DaoProcess_InterceptReturnValue( proc ); if( execute ) DaoProcess_Execute( proc ); return 0; InvalidParam: DaoProcess_ShowCallError( proc, (DaoRoutine*)V, O, P, N, DVM_CALL ); return DAO_ERROR_PARAM; }
static void DaoCallThread_Run( DaoCallThread *self ) { DaoCallServer *server = daoCallServer; double wt = 0.001; daoint i, count, timeout; self->thdData = DThread_GetSpecific(); if( self->taskFunc ){ self->taskFunc( self->taskParam ); self->taskOwner = NULL; } while( server->vmspace->stopit == 0 ){ DaoProcess *process = NULL; DaoFuture *future = NULL; DThreadTask function = NULL; void *parameter = NULL; if( self->thdData != NULL ) self->thdData->state = 0; DMutex_Lock( & server->mutex ); server->idle += 1; server->vacant += self->taskOwner == NULL; while( server->pending->size == (server->events2->size + server->waitings->size) ){ //printf( "%p %i %i %i %i\n", self, server->events->size, server->pending->size, server->events2->size, server->waitings->size ); if( server->vmspace->stopit ) break; if( server->finishing && server->vacant == server->total ){ if( (server->events2->size + server->waitings->size) == 0 ) break; } wt = 0.01*(server->idle == server->total) + 0.001; timeout = DCondVar_TimedWait( & server->condv, & server->mutex, wt ); } for(i=0; i<server->parameters->size; ++i){ void *param = server->parameters->items.pVoid[i]; if( DMap_Find( server->active, param ) ) continue; DMap_Insert( server->active, param, NULL ); self->taskOwner = server->owners->items.pVoid[i]; function = (DThreadTask) server->functions->items.pVoid[i]; parameter = param; DList_Erase( server->functions, i, 1 ); DList_Erase( server->parameters, i, 1 ); DList_Erase( server->owners, i, 1 ); DMap_Erase( server->pending, parameter ); server->idle -= 1; server->vacant -= 1; break; } DMutex_Unlock( & server->mutex ); if( server->vmspace->stopit ) break; if( function ){ (*function)( parameter ); self->taskOwner = NULL; DMutex_Lock( & server->mutex ); DMap_Erase( server->active, parameter ); DMutex_Unlock( & server->mutex ); continue; } if( server->pending->size == 0 && server->finishing && server->vacant == server->total ) break; DMutex_Lock( & server->mutex ); server->idle -= 1; server->vacant -= self->taskOwner == NULL; future = DaoCallServer_GetNextFuture(); DMutex_Unlock( & server->mutex ); if( future == NULL ) continue; process = future->process; if( process == NULL ){ GC_DecRC( future ); continue; } count = process->exceptions->size; future->state = DAO_CALL_RUNNING; DaoProcess_InterceptReturnValue( process ); DaoProcess_Start( process ); if( process->exceptions->size > count ) DaoProcess_PrintException( process, NULL, 1 ); if( process->status <= DAO_PROCESS_ABORTED ) self->taskOwner = NULL; if( future->actor ){ int erase = 1; DMutex_Lock( & server->mutex ); if( future->actor->rootObject->isAsync ){ erase = process->status == DAO_PROCESS_FINISHED; } if( erase ) DMap_Erase( server->active, future->actor->rootObject ); DMutex_Unlock( & server->mutex ); } DMutex_Lock( & server->mutex ); DMap_Erase( server->active, process ); process->active = 0; DMutex_Unlock( & server->mutex ); DaoProcess_ReturnFutureValue( process, future ); if( future->state == DAO_CALL_FINISHED ) DaoFuture_ActivateEvent( future ); GC_DecRC( future ); } DMutex_Lock( & server->mutex ); server->stopped += 1; DMutex_Unlock( & server->mutex ); }
void DaoCallServer_AddCall( DaoProcess *caller ) { DaoFuture *future; DaoTaskEvent *event; DaoProcess *callee = DaoVmSpace_AcquireProcess( caller->vmSpace ); DaoStackFrame *frame = caller->topFrame; DaoRoutine *routine = frame->routine; DaoType *type = (DaoType*) routine->routType->aux; DaoValue **params = caller->stackValues + caller->topFrame->stackBase; int i, count = caller->topFrame->parCount; if( caller->activeCode->b & DAO_CALL_BLOCK ){ DaoValue **calleeValues, **callerValues = caller->activeValues; DaoStackFrame *sectFrame = DaoProcess_FindSectionFrame( caller ); DaoStackFrame *callerFrame = caller->topFrame->prev; DaoVmCode *vmc, *end, *sect; if( sectFrame != callerFrame ){ DaoVmSpace_ReleaseProcess( caller->vmSpace, callee ); DaoProcess_RaiseError( caller, NULL, "Invalid code section" ); return; } if( routine->body ){ DaoProcess_PushRoutine( callee, callerFrame->routine, callerFrame->object ); callerValues = caller->stackValues + callerFrame->stackBase; }else{ DaoProcess_PushRoutine( callee, caller->activeRoutine, caller->activeObject ); } DaoProcess_SetActiveFrame( callee, callee->topFrame ); calleeValues = callee->stackValues + callee->topFrame->stackBase; callee->activeCode = caller->activeCode; vmc = callerFrame->routine->body->vmCodes->data.codes + callerFrame->entry; end = callerFrame->routine->body->vmCodes->data.codes + vmc->b; sect = vmc + 1; for(vmc=sect; vmc!=end; vmc++){ int i = -1, code = vmc->code; if( code == DVM_GETVH || (code >= DVM_GETVH_I && code <= DVM_GETVH_C) ){ i = vmc->b; }else if( code == DVM_SETVH || (code >= DVM_SETVH_II && code <= DVM_SETVH_CC) ){ i = vmc->b; } if( i >= 0 ) DaoValue_Move( callerValues[i], & calleeValues[i], NULL ); } } future = DaoFuture_New( type, 1 ); future->state = DAO_CALL_PAUSED; future->actor = caller->topFrame->object; GC_IncRC( future->actor ); GC_Assign( & future->process, callee ); GC_Assign( & callee->future, future ); callee->parCount = count; /* Use routine->parCount instead of caller->topFrame->parCount, for default parameters: */ for(i=0; i<routine->parCount; ++i) DaoValue_Copy( params[i], & callee->paramValues[i] ); if( routine->body ){ DaoProcess_PushRoutine( callee, routine, future->actor ); }else{ DaoProcess_PushFunction( callee, routine ); callee->activeNamespace = caller->activeNamespace; } if( caller->activeCode->b & DAO_CALL_BLOCK ){ callee->topFrame->host = callee->topFrame; callee->topFrame->retmode = DVM_RET_PROCESS; callee->topFrame->returning = 0; } #ifdef DAO_WITH_CONCURRENT DaoCallServer_TryInit( mainVmSpace ); event = DaoCallServer_MakeEvent(); DaoTaskEvent_Init( event, DAO_EVENT_RESUME_TASKLET, DAO_EVENT_RESUME, future, NULL ); DaoProcess_PopFrame( caller ); DaoProcess_PutValue( caller, (DaoValue*) future ); DaoCallServer_Add( event ); #else DaoProcess_PopFrame( caller ); DaoProcess_PutValue( caller, (DaoValue*) future ); DaoProcess_InterceptReturnValue( callee ); DaoProcess_Execute( callee ); DaoProcess_ReturnFutureValue( callee, future ); DaoVmSpace_ReleaseProcess( caller->vmSpace, callee ); #endif }
static void DaoCallThread_Run( DaoCallThread *self ) { DaoCallServer *server = daoCallServer; double wt = 0.001; daoint i, timeout; self->thdData = DThread_GetSpecific(); if( self->taskFunc ) self->taskFunc( self->taskParam ); while(1){ DaoProcess *process = NULL; DaoFuture *future = NULL; DThreadTask function = NULL; void *parameter = NULL; self->thdData->state = 0; DMutex_Lock( & server->mutex ); server->idle += 1; while( server->pending->size == (server->events2->size + server->waitings->size) ){ //printf( "%p %i %i %i %i\n", self, server->events->size, server->pending->size, server->events2->size, server->waitings->size ); if( server->finishing && server->idle == server->total ){ if( (server->events2->size + server->waitings->size) == 0 ) break; } timeout = DCondVar_TimedWait( & server->condv, & server->mutex, wt ); } for(i=0; i<server->parameters->size; ++i){ void *param = server->parameters->items.pVoid[i]; if( DMap_Find( server->active, param ) ) continue; DMap_Insert( server->active, param, NULL ); function = (DThreadTask) server->functions->items.pVoid[i]; parameter = param; DArray_Erase( server->functions, i, 1 ); DArray_Erase( server->parameters, i, 1 ); DMap_Erase( server->pending, parameter ); server->idle -= 1; break; } DMutex_Unlock( & server->mutex ); if( function ){ (*function)( parameter ); DMutex_Lock( & server->mutex ); DMap_Erase( server->active, parameter ); DMutex_Unlock( & server->mutex ); continue; } if( server->pending->size == 0 && server->finishing && server->idle == server->total ) break; DMutex_Lock( & server->mutex ); server->idle -= 1; future = DaoCallServer_GetNextFuture(); DMutex_Unlock( & server->mutex ); if( future == NULL ) continue; process = future->process; if( process == NULL ){ GC_DecRC( future ); continue; } if( process->pauseType == DAO_PAUSE_NATIVE_THREAD ){ DMutex_Lock( & server->mutex ); process->pauseType = 0; /* TODO: demo/concurrent/future.dao */ if( process->condv ) DCondVar_Signal( process->condv ); DMutex_Unlock( & server->mutex ); }else{ int count = process->exceptions->size; future->state = DAO_CALL_RUNNING; DaoProcess_InterceptReturnValue( process ); DaoProcess_Execute( process ); if( process->exceptions->size > count ) DaoProcess_PrintException( process, 1 ); } if( future->actor ){ DMutex_Lock( & server->mutex ); DMap_Erase( server->active, future->actor->rootObject ); DMutex_Unlock( & server->mutex ); } DMutex_Lock( & server->mutex ); DMap_Erase( server->active, process ); DMutex_Unlock( & server->mutex ); DaoProcess_ReturnFutureValue( process, future ); if( future->state == DAO_CALL_FINISHED ) DaoFuture_ActivateEvent( future ); GC_DecRC( future ); } DMutex_Lock( & server->mutex ); server->stopped += 1; DMutex_Unlock( & server->mutex ); }