Ejemplo n.º 1
0
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 );
	}
}
Ejemplo n.º 2
0
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 );
}
Ejemplo n.º 3
0
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 );
}
Ejemplo n.º 4
0
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 );
}
Ejemplo n.º 5
0
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 );
}
Ejemplo n.º 6
0
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 );
	}
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
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;
}