static void TEST_AssertError( DaoProcess *proc, DaoValue* p[], int N ) { DString *expected = p[0]->xString.value; DString *actual = NULL; DList *errors = proc->exceptions; DaoVmCode *sect = DaoProcess_InitCodeSection( proc, 0 ); int catched = 0; int size = errors->size; if( sect == NULL ) return; DaoProcess_Execute( proc ); if ( proc->status == DAO_PROCESS_ABORTED && errors->size > size ){ DaoException *e = (DaoException*)&errors->items.pValue[errors->size - 1]->xCdata; if ( DString_Compare( expected, e->ctype->name ) != 0 ) actual = DString_Copy( e->ctype->name ); else catched = 1; DList_Clear( errors ); } DaoProcess_PopFrame( proc ); if ( !catched ){ char buf[512]; if ( actual ){ snprintf( buf, sizeof(buf), "expected %s error, intercepted %s", expected->chars, actual->chars ); DString_Delete( actual ); } else snprintf( buf, sizeof(buf), "expected %s error, intercepted nothing", expected->chars ); DaoProcess_RaiseError( proc, "Test::AssertError", buf ); } }
static void DaoMT_Critical( DaoProcess *proc, DaoValue *p[], int n ) { void *key; DNode *it; DMap *cache = (DMap*) DaoProcess_GetAuxData( proc, DaoMT_ProcMutexCache ); DaoVmCode *sect = DaoProcess_InitCodeSection( proc, 0 ); DaoRoutine *routine = proc->activeRoutine; if( sect == NULL ) return; /* Get the original routine, if this one is a specialized copy: */ while( routine->original ) routine = routine->original; /* // Use "routine + sect->c" instead of "sect" as the key for mutex, // as "sect" may be different for different copy of specialized routine. // But "sect->c" won't change after being set during compiling. */ key = routine + sect->c; if( cache == NULL ){ cache = DHash_New(0,0); /* Local cache is used to avoid extra locking; */ DaoProcess_SetAuxData( proc, DaoMT_ProcMutexCache, cache ); } it = DMap_Find( cache, key ); /* Check local cache first; */ if( it == NULL ) it = DMap_Insert( cache, key, DaoMT_GetMutex( routine, key ) ); DMutex_Lock( (DMutex*) it->value.pVoid ); DaoProcess_Execute( proc ); DMutex_Unlock( (DMutex*) it->value.pVoid ); DaoProcess_PopFrame( proc ); }
static void DaoStream_ReadLines( DaoStream *self, DaoList *list, DaoProcess *proc, int count, int chop ) { DaoValue *res; DaoString *line; DaoVmCode *sect = DaoProcess_InitCodeSection( proc, 1 ); daoint i = 0; if( sect == NULL ){ line = DaoString_New(); while( (count == 0 || (i++) < count) && DaoStream_ReadLine( self, line->value ) ){ if( line->value->size == 0 && self->AtEnd != NULL && self->AtEnd( self ) ) break; if( chop ) DString_Chop( line->value, 0 ); DaoList_Append( list, (DaoValue*) line ); } DaoString_Delete( line ); }else{ ushort_t entry = proc->topFrame->entry; if( sect->b ){ DaoString tmp = {DAO_STRING,0,0,0,1,NULL}; DString tmp2 = DString_WrapChars( "" ); tmp.value = & tmp2; line = (DaoString*) DaoProcess_SetValue( proc, sect->a, (DaoValue*)(void*) &tmp ); } while( (count == 0 || (i++) < count) && DaoStream_ReadLine( self, line->value ) ){ if( line->value->size == 0 && self->AtEnd != NULL && self->AtEnd( self ) ) break; if( chop ) DString_Chop( line->value, 0 ); proc->topFrame->entry = entry; DaoProcess_Execute( proc ); if( proc->status == DAO_PROCESS_ABORTED ) break; res = proc->stackValues[0]; if( res && res->type != DAO_NONE ) DaoList_Append( list, res ); } DaoProcess_PopFrame( proc ); } }
static void DaoMT_InitProcess( DaoProcess *proto, DaoProcess *clone, int argcount ) { DaoProcess_PushRoutine( clone, proto->activeRoutine, proto->activeObject ); clone->activeCode = proto->activeCode; DaoProcess_PushFunction( clone, proto->topFrame->routine ); DaoProcess_InitCodeSection( clone, argcount ); clone->topFrame->outer = proto; clone->topFrame->host = proto->topFrame->prev; clone->topFrame->retmode = DVM_RET_PROCESS; clone->topFrame->returning = 0; }
static void NODE_Search( DaoProcess *proc, DaoValue *p[], int N ) { DList *nodes; DaoList *list = DaoProcess_PutList( proc ); DaoxNode *self = (DaoxNode*) p[0]; DaoVmCode *sect = DaoProcess_InitCodeSection( proc, 1 ); daoint method = p[1]->xEnum.value; daoint which = p[2]->xEnum.value; daoint i, j, entry; if( sect == NULL ) return; for(i=0; i<self->graph->nodes->size; i++){ DaoxNode *node = (DaoxNode*) self->graph->nodes->items.pVoid[i]; node->state = 0; } nodes = DList_New(0); DList_PushBack( nodes, self ); entry = proc->topFrame->entry; while( nodes->size ){ DaoxNode *node = NULL; if( method ){ node = (DaoxNode*) DList_Front( nodes ); DList_PopFront( nodes ); }else{ node = (DaoxNode*) DList_Back( nodes ); DList_PopBack( nodes ); } if( node->state ) continue; node->state = 1; if( sect->b >0 ) DaoProcess_SetValue( proc, sect->a, (DaoValue*) node ); proc->topFrame->entry = entry; DaoProcess_Execute( proc ); if( proc->status == DAO_PROCESS_ABORTED ) break; if( proc->stackValues[0]->xInteger.value ){ DaoList_PushBack( list, (DaoValue*) node ); if( which == 0 ) break; } for(j=0; j<node->outs->size; j++){ DaoxEdge *edge = (DaoxEdge*) node->outs->items.pVoid[j]; DaoxNode *node2 = node == edge->first ? edge->second : edge->first; DList_PushBack( nodes, node2 ); } } DaoProcess_PopFrame( proc ); DList_Delete( nodes ); }
static void DaoSTD_Exec( DaoProcess *proc, DaoValue *p[], int n ) { DaoVmCode *sect = DaoProcess_InitCodeSection( proc, 0 ); int ecount = proc->exceptions->size; if( sect == NULL ) return; DaoProcess_Execute( proc ); DaoProcess_PopFrame( proc ); if( proc->exceptions->size > ecount ){ if( n > 0 ){ DaoProcess_PutValue( proc, p[0] ); DList_Erase( proc->exceptions, ecount, -1 ); } }else{ DaoProcess_PutValue( proc, proc->stackValues[0] ); } }
static void DaoSTD_Try( DaoProcess *proc, DaoValue *p[], int n ) { DaoVmCode *sect = DaoProcess_InitCodeSection( proc, 0 ); int i, ecount = proc->exceptions->size; if( sect == NULL ) return; DaoProcess_Execute( proc ); DaoProcess_PopFrame( proc ); if( proc->exceptions->size > (ecount+1) ){ DaoList *list = DaoProcess_PutList( proc ); for(i=ecount; i<proc->exceptions->size; ++i){ DaoList_Append( list, proc->exceptions->items.pValue[i] ); } DList_Erase( proc->exceptions, ecount, -1 ); }else if( proc->exceptions->size > ecount ){ DaoProcess_PutValue( proc, proc->exceptions->items.pValue[proc->exceptions->size-1] ); DList_PopBack( proc->exceptions ); }else{ DaoProcess_PutValue( proc, proc->stackValues[0] ); } }
static void DaoMT_Start( DaoProcess *proc, DaoValue *p[], int n ) { DaoProcess *clone; DaoVmCode *vmc, *end, *sect; DaoType *type = DaoProcess_GetReturnType( proc ); DaoFuture *future = DaoFuture_New( type, 0 ); int entry, nop = proc->activeCode[1].code == DVM_NOP; DaoProcess_PutValue( proc, (DaoValue*) future ); sect = DaoProcess_InitCodeSection( proc, 0 ); if( sect == NULL ) return; entry = proc->topFrame->entry; end = proc->activeRoutine->body->vmCodes->data.codes + proc->activeCode[nop+1].b; clone = DaoVmSpace_AcquireProcess( proc->vmSpace ); DaoProcess_PopFrame( proc ); DaoMT_InitProcess( proc, clone, 0 ); clone->topFrame->entry = entry; /* // Use the cloned process instead of the parent process, in case that // the cloned process will not be joined by the parent process: */ clone->topFrame->outer = clone; future->process = clone; GC_IncRC( clone ); GC_Assign( & clone->future, future ); future->state = DAO_CALL_RUNNING; 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( proc->activeValues[i], & clone->activeValues[i], NULL ); } DaoCallServer_AddTask( DaoMT_Start0, clone, p[0]->xEnum.value ? clone : NULL ); }
static void GRAPH_FindEdges( DaoProcess *proc, DaoValue *p[], int N ) { DaoxGraph *self = (DaoxGraph*) p[0]; DaoList *list = DaoProcess_PutList( proc ); DaoVmCode *sect = DaoProcess_InitCodeSection( proc, 1 ); daoint which = p[1]->xEnum.value; daoint i, j, entry; if( sect == NULL ) return; entry = proc->topFrame->entry; for(i=0; i<self->edges->size; i++){ DaoxEdge *edge = (DaoxEdge*) self->edges->items.pVoid[i]; if( sect->b >0 ) DaoProcess_SetValue( proc, sect->a, (DaoValue*) edge ); proc->topFrame->entry = entry; DaoProcess_Execute( proc ); if( proc->status == DAO_PROCESS_ABORTED ) break; if( proc->stackValues[0]->xInteger.value ){ DaoList_PushBack( list, (DaoValue*) edge ); if( which == 0 ) break; } } DaoProcess_PopFrame( proc ); }
static void DaoMT_Functional( DaoProcess *proc, DaoValue *P[], int N, int F ) { DMutex mutex; DCondVar condv; DaoTaskData *tasks; DaoValue *param = P[0]; DaoValue *result = NULL; DaoList *list = NULL; DaoArray *array = NULL; DaoVmCode *sect = NULL; DaoStackFrame *frame = DaoProcess_FindSectionFrame( proc ); int i, entry, threads = P[1]->xInteger.value; daoint index = -1, status = 0, joined = 0; DNode *node = NULL; switch( F ){ case DVM_FUNCT_MAP : if( param->type == DAO_ARRAY ){ array = DaoProcess_PutArray( proc ); result = (DaoValue*) array; }else{ list = DaoProcess_PutList( proc ); result = (DaoValue*) list; } break; case DVM_FUNCT_FIND : DaoProcess_PutValue( proc, dao_none_value ); break; } if( threads <= 0 ) threads = 2; if( frame != proc->topFrame->prev ){ DaoProcess_RaiseError( proc, NULL, "Invalid code section from non-immediate caller" ); return; } sect = DaoProcess_InitCodeSection( proc, 0 ); if( sect == NULL ) return; if( list ){ DList_Clear( list->value ); if( param->type == DAO_LIST ) DList_Resize( list->value, param->xList.value->size, NULL ); if( param->type == DAO_MAP ) DList_Resize( list->value, param->xMap.value->size, NULL ); #ifdef DAO_WITH_NUMARRAY }else if( array && F == DVM_FUNCT_MAP ){ DaoArray_GetSliceShape( (DaoArray*) param, & array->dims, & array->ndim ); DaoArray_ResizeArray( array, array->dims, array->ndim ); #endif } DMutex_Init( & mutex ); DCondVar_Init( & condv ); entry = proc->topFrame->entry; tasks = (DaoTaskData*) dao_calloc( threads, sizeof(DaoTaskData) ); DaoProcess_PopFrame( proc ); for(i=0; i<threads; i++){ DaoTaskData *task = tasks + i; task->param = param; task->result = result; task->proto = proc; task->sect = sect; task->funct = F; task->entry = entry; task->first = i; task->step = threads; task->index = & index; task->node = & node; task->joined = & joined; task->condv = & condv; task->mutex = & mutex; task->clone = DaoVmSpace_AcquireProcess( proc->vmSpace ); if( i ) DaoCallServer_AddTask( DaoMT_RunFunctional, task, task->clone ); } DaoMT_RunFunctional( tasks ); DMutex_Lock( & mutex ); while( joined < threads ) DCondVar_TimedWait( & condv, & mutex, 0.01 ); DMutex_Unlock( & mutex ); for(i=0; i<threads; i++){ DaoTaskData *task = tasks + i; DaoVmSpace_ReleaseProcess( proc->vmSpace, task->clone ); status |= task->status; } if( F == DVM_FUNCT_FIND ){ DaoTuple *tuple = DaoProcess_PutTuple( proc, 2 ); if( param->type == DAO_LIST && index != -1 ){ DaoValue **items = param->xList.value->items.pValue; GC_Assign( & tuple->values[1], items[index] ); tuple->values[0]->xInteger.value = index; }else if( param->type == DAO_MAP && node ){ GC_Assign( & tuple->values[0], node->key.pValue ); GC_Assign( & tuple->values[1], node->value.pValue ); } } if( status ) DaoProcess_RaiseError( proc, NULL, "code section execution failed!" ); DMutex_Destroy( & mutex ); DCondVar_Destroy( & condv ); dao_free( tasks ); }