static void CHANNEL_Send( DaoProcess *proc, DaoValue *par[], int N ) { DaoValue *data; DaoFuture *future = DaoProcess_GetInitFuture( proc ); DaoChannel *self = (DaoChannel*) par[0]; float timeout = par[2]->xFloat.value; if( DaoProcess_CheckCB( proc, "cannot send/block inside code section method" ) ) return; if( self->cap <= 0 ){ DaoProcess_RaiseException( proc, DAO_ERROR_PARAM, "channel is closed" ); return; } data = DaoValue_DeepCopy( par[1] ); if( data == NULL ){ DaoProcess_RaiseException( proc, DAO_ERROR_PARAM, "invalid data for the channel" ); return; } //printf( "CHANNEL_Send: %p\n", event ); DMutex_Lock( & daoCallServer->mutex ); DArray_Append( self->buffer, data ); DaoChannel_ActivateEvent( self, DAO_EVENT_WAIT_RECEIVING ); DaoChannel_ActivateEvent( self, DAO_EVENT_WAIT_SELECT ); DCondVar_Signal( & daoCallServer->condv ); DMutex_Unlock( & daoCallServer->mutex ); if( self->buffer->size >= self->cap ){ DaoTaskEvent *event = DaoCallServer_MakeEvent(); DaoTaskEvent_Init( event, DAO_EVENT_WAIT_SENDING, DAO_EVENT_WAIT, future, self ); proc->status = DAO_PROCESS_SUSPENDED; proc->pauseType = DAO_PAUSE_CHANNEL_SEND; DaoCallServer_AddTimedWait( proc, event, timeout ); } }
void DaoChannel_Send( DaoChannel *self, DaoValue *data ) { DMutex_Lock( & daoCallServer->mutex ); DList_Append( self->buffer, data ); DaoChannel_ActivateEvent( self, DAO_EVENT_WAIT_RECEIVING ); DaoChannel_ActivateEvent( self, DAO_EVENT_WAIT_SELECT ); DCondVar_Signal( & daoCallServer->condv ); DMutex_Unlock( & daoCallServer->mutex ); }
void DaoMT_Select( DaoProcess *proc, DaoValue *par[], int n ) { DNode *it; DaoTaskEvent *event = NULL; DaoFuture *future = DaoProcess_GetInitFuture( proc ); DaoMap *selects = (DaoMap*) par[0]; float timeout = par[1]->xFloat.value; for(it=DaoMap_First(selects); it; it=DaoMap_Next(selects,it)){ DaoValue *value = it->key.pValue; int isfut = DaoValue_CheckCtype( value, dao_type_future ); int ischan = DaoValue_CheckCtype( value, dao_type_channel ); if( isfut == 0 && ischan == 0 ){ DaoProcess_RaiseError( proc, "Param", "invalid type selection" ); return; } } event = DaoCallServer_MakeEvent(); DaoTaskEvent_Init( event, DAO_EVENT_WAIT_SELECT, DAO_EVENT_WAIT, future, NULL ); GC_Assign( & event->selects, selects ); proc->status = DAO_PROCESS_SUSPENDED; proc->pauseType = DAO_PAUSE_CHANFUT_SELECT; DaoCallServer_AddTimedWait( proc, event, timeout ); /* Message may have been sent before this call: */ DMutex_Lock( & daoCallServer->mutex ); DaoChannel_ActivateEvent( NULL, DAO_EVENT_WAIT_SELECT ); DCondVar_Signal( & daoCallServer->condv ); DMutex_Unlock( & daoCallServer->mutex ); }
void CHANNEL_Select( DaoProcess *proc, DaoValue *par[], int n ) { DaoTaskEvent *event = NULL; DaoFuture *future = DaoProcess_GetInitFuture( proc ); DaoList *channels = (DaoList*) par[0]; float timeout = par[1]->xFloat.value; daoint i, size = DaoList_Size( channels ); for(i=0; i<size; ++i){ DaoValue *value = DaoList_GetItem( channels, i ); if( DaoValue_CheckCtype( value, dao_type_channel ) == 0 ){ DaoProcess_RaiseException( proc, DAO_ERROR_PARAM, "invalid type selection" ); return; } } event = DaoCallServer_MakeEvent(); DaoTaskEvent_Init( event, DAO_EVENT_WAIT_SELECT, DAO_EVENT_WAIT, future, NULL ); event->channels = DArray_Copy( & channels->items ); proc->status = DAO_PROCESS_SUSPENDED; proc->pauseType = DAO_PAUSE_CHANFUT_SELECT; DaoCallServer_AddTimedWait( proc, event, timeout ); /* Message may have been sent before this call: */ DMutex_Lock( & daoCallServer->mutex ); DaoChannel_ActivateEvent( NULL, DAO_EVENT_WAIT_SELECT ); DCondVar_Signal( & daoCallServer->condv ); DMutex_Unlock( & daoCallServer->mutex ); }
static void CHANNEL_Cap( DaoProcess *proc, DaoValue *par[], int N ) { DaoChannel *self = (DaoChannel*) par[0]; daoint i; DaoProcess_PutInteger( proc, self->cap ); if( N == 1 ) return; /* Closing the channel: */ DMutex_Lock( & daoCallServer->mutex ); self->cap = par[1]->xInteger.value; if( self->cap == 0 ){ DaoChannel_ActivateEvent( self, DAO_EVENT_WAIT_RECEIVING ); DaoChannel_ActivateEvent( self, DAO_EVENT_WAIT_SELECT ); DCondVar_Signal( & daoCallServer->condv ); } DMutex_Unlock( & daoCallServer->mutex ); }
static void CHANNEL_Receive( DaoProcess *proc, DaoValue *par[], int N ) { DaoTaskEvent *event = NULL; DaoFuture *future = DaoProcess_GetInitFuture( proc ); DaoChannel *self = (DaoChannel*) par[0]; float timeout = par[1]->xFloat.value; event = DaoCallServer_MakeEvent(); DaoTaskEvent_Init( event, DAO_EVENT_WAIT_RECEIVING, DAO_EVENT_WAIT, future, self ); proc->status = DAO_PROCESS_SUSPENDED; proc->pauseType = DAO_PAUSE_CHANNEL_RECEIVE; DaoCallServer_AddTimedWait( proc, event, timeout ); /* Message may have been sent before this call: */ if( self->buffer->size ){ DMutex_Lock( & daoCallServer->mutex ); DaoChannel_ActivateEvent( self, DAO_EVENT_WAIT_RECEIVING ); DCondVar_Signal( & daoCallServer->condv ); DMutex_Unlock( & daoCallServer->mutex ); } }
static DaoFuture* DaoCallServer_GetNextFuture() { DaoCallServer *server = daoCallServer; DaoFuture *first, *future, *precond; DList *events = server->events; DMap *pending = server->pending; DMap *active = server->active; DNode *it; daoint i, j; for(i=0; i<events->size; i++){ DaoTaskEvent *event = (DaoTaskEvent*) events->items.pVoid[i]; DaoFuture *future = event->future; DaoObject *actor = future->actor; DaoChannel *channel = event->channel; DaoChannel *closed = NULL; DaoChannel *chselect = NULL; DaoFuture *futselect = NULL; DaoValue *selected = NULL; DaoValue *message = NULL; int type = event->type; if( event->state == DAO_EVENT_WAIT && future->precond != NULL ){ if( future->precond->state != DAO_CALL_FINISHED ) goto MoveToWaiting; } switch( event->type ){ case DAO_EVENT_WAIT_SENDING : if( channel->buffer->size >= channel->cap ){ if( event->state == DAO_EVENT_WAIT ){ DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_RECEIVING ); DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_SELECT ); goto MoveToWaiting; } } event->type = DAO_EVENT_RESUME_TASKLET; break; case DAO_EVENT_WAIT_RECEIVING : if( channel->buffer->size == 0 ){ if( channel->cap > 0 && event->state == DAO_EVENT_WAIT ){ DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_SENDING ); goto MoveToWaiting; } message = dao_none_value; }else{ message = channel->buffer->items.pValue[0]; } GC_Assign( & event->message, message ); event->auxiliary = channel->cap <= 0 && channel->buffer->size == 0; event->type = DAO_EVENT_RESUME_TASKLET; DList_PopFront( channel->buffer ); if( channel->buffer->size < channel->cap ) DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_SENDING ); if( channel->buffer->size ) DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_RECEIVING ); break; case DAO_EVENT_WAIT_SELECT : message = dao_none_value; for(it=DaoMap_First(event->selects); it; it=DaoMap_Next(event->selects,it)){ if( DaoValue_CheckCtype( it->key.pValue, dao_type_channel ) ){ DaoChannel *chan = (DaoChannel*) it->key.pValue; if( chan->buffer->size > 0 ){ chselect = chan; selected = it->key.pValue; message = chan->buffer->items.pValue[0]; closed = NULL; break; }else if( chan->cap == 0 ){ closed = chan; } }else{ DaoFuture *fut = (DaoFuture*) it->key.pValue; if( fut->state == DAO_CALL_FINISHED ){ futselect = fut; selected = it->key.pValue; message = fut->value; break; } } } if( selected == NULL ) selected = (DaoValue*) closed; if( event->state == DAO_EVENT_WAIT && event->selects->value->size ){ if( selected == NULL ) goto MoveToWaiting; } GC_Assign( & event->message, message ); GC_Assign( & event->selected, selected ); event->auxiliary = event->selects->value->size == 0; event->type = DAO_EVENT_RESUME_TASKLET; /* change status to not finished: */ if( chselect != NULL || futselect != NULL ) event->auxiliary = 0; if( chselect ){ DList_PopFront( chselect->buffer ); if( chselect->buffer->size < chselect->cap ) DaoChannel_ActivateEvent( chselect, DAO_EVENT_WAIT_SENDING ); if( chselect->buffer->size ) DaoChannel_ActivateEvent( chselect, DAO_EVENT_WAIT_SELECT ); } if( futselect != NULL || closed != NULL ){ void *key = futselect ? (void*)futselect : (void*)closed; DMap_Erase( event->selects->value, key ); } break; default: break; } if( actor ){ DNode *it = DMap_Find( active, actor->rootObject ); if( actor->rootObject->isAsync ){ if( it && it->value.pVoid != (void*) future ) continue; }else if( it ){ continue; } } if( future->process && DMap_Find( active, future->process ) ) continue; DList_Erase( events, i, 1 ); DMap_Erase( pending, event ); if( actor ){ void *value = actor->rootObject->isAsync ? future : NULL; DMap_Insert( active, actor->rootObject, value ); } if( future->process ){ DMap_Insert( active, future->process, NULL ); future->process->active = 1; } /* // DaoValue_Move() should be used instead of GC_Assign() for thread safety. // Because using GC_Assign() here, may caused "future->message" of primitive // type being deleted, right after DaoFuture_GetGCFields() has retrieved it // for GC scanning. */ DaoValue_Move( event->message, & future->message, NULL ); DaoValue_Move( event->selected, & future->selected, NULL ); future->aux1 = event->auxiliary; future->timeout = event->timeout; GC_IncRC( future ); /* To be decreased at the end of tasklet; */ DaoCallServer_CacheEvent( event ); return future; MoveToWaiting: if( event->expiring >= 0.0 && event->expiring < MIN_TIME ) continue; if( event->expiring >= MIN_TIME ){ dao_complex com = {0.0,0.0}; com.real = event->expiring; DMap_Insert( server->waitings, & com, event ); DCondVar_Signal( & server->condv2 ); }else{ DList_Append( server->events2, event ); } DList_Erase( server->events, i, 1 ); i -= 1; } return NULL; }
static DaoFuture* DaoCallServer_GetNextFuture() { DaoCallServer *server = daoCallServer; DaoFuture *first, *future, *precond; DArray *events = server->events; DMap *pending = server->pending; DMap *active = server->active; daoint i, j; for(i=0; i<events->size; i++){ DaoTaskEvent *event = (DaoTaskEvent*) events->items.pVoid[i]; DaoFuture *future = event->future; DaoChannel *channel = event->channel; DaoChannel *selected = NULL; DaoValue *message = NULL; int closed = 0; switch( event->type ){ case DAO_EVENT_WAIT_SENDING : if( channel->buffer->size >= channel->cap ){ if( event->state == DAO_EVENT_WAIT ) goto MoveToWaiting; } break; case DAO_EVENT_WAIT_RECEIVING : if( channel->buffer->size == 0 ){ if( channel->cap > 0 && event->state == DAO_EVENT_WAIT ) goto MoveToWaiting; message = dao_none_value; }else{ message = channel->buffer->items.pValue[0]; } GC_ShiftRC( message, event->future->message ); event->future->message = message; event->future->aux1 = channel->cap <= 0 && channel->buffer->size == 0; DArray_PopFront( channel->buffer ); if( channel->buffer->size < channel->cap ) DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_SENDING ); if( channel->buffer->size ) DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_RECEIVING ); break; case DAO_EVENT_WAIT_SELECT : for(j=0; j<event->channels->size; ++j){ DaoChannel *chan = (DaoChannel*) event->channels->items.pValue[j]; if( chan->buffer->size > 0 ){ selected = chan; break; }else if( chan->cap <= 0 ){ closed += 1; } } if( selected == NULL && closed < event->channels->size ){ if( event->state == DAO_EVENT_WAIT ) goto MoveToWaiting; } if( selected == NULL || selected->buffer->size == 0 ){ if( event->state == DAO_EVENT_WAIT ) goto MoveToWaiting; message = dao_none_value; }else{ message = selected->buffer->items.pValue[0]; } GC_ShiftRC( message, event->future->message ); GC_ShiftRC( selected, event->future->selected ); event->future->message = message; event->future->selected = (DaoValue*) selected; event->future->aux1 = closed == event->channels->size; if( selected ){ DArray_PopFront( selected->buffer ); if( selected->buffer->size < selected->cap ) DaoChannel_ActivateEvent( selected, DAO_EVENT_WAIT_SENDING ); if( selected->buffer->size ) DaoChannel_ActivateEvent( selected, DAO_EVENT_WAIT_SELECT ); } break; default: break; } if( event->state == DAO_EVENT_WAIT && future->precond != NULL ){ if( future->precond->state != DAO_CALL_FINISHED ) goto MoveToWaiting; } if( future->actor && DMap_Find( active, future->actor->rootObject ) ) continue; if( future->process && DMap_Find( active, future->process ) ) continue; DArray_Erase( events, i, 1 ); DMap_Erase( pending, event ); if( future->actor ) DMap_Insert( active, future->actor->rootObject, NULL ); if( future->process ) DMap_Insert( active, future->process, NULL ); GC_IncRC( future ); /* To be decreased at the end of tasklet; */ future->timeout = event->timeout; DaoCallServer_CacheEvent( event ); return future; MoveToWaiting: if( event->expiring >= 0.0 && event->expiring < MIN_TIME ) continue; if( event->expiring >= MIN_TIME ){ DaoComplex com = {DAO_COMPLEX,0,0,0,1,{0.0,0.0}}; com.value.real = event->expiring; DMap_Insert( server->waitings, & com, event ); DCondVar_Signal( & server->condv2 ); }else{ DArray_Append( server->events2, event ); } DArray_Erase( server->events, i, 1 ); i -= 1; } return NULL; }