unsigned PutPipeTimed(Pipe_t *p, void *data, unsigned size, unsigned msecs) { unsigned nbytes; char *d; if ( !size || !EnterMonitor(p->monitor) ) return 0; // No se pueden escribir más bytes que el tamaño del pipe if ( size > p->size ) size = p->size; // Si hay un timeout finito, calcular deadline. Time_t deadline = (msecs && msecs != FOREVER) ? Time() + msecs : 0; // Para que la escritura sea atómica, esperar a que haya lugar para escribir todos los bytes while ( (p->size - p->avail) < size ) { // Desistir si es condicional, si no esperar if ( !msecs || !WaitConditionTimed(p->cond_put, msecs) ) { LeaveMonitor(p->monitor); return 0; } // Si hay que seguir esperando con deadline, recalcular timeout if ( deadline && (p->size - p->avail) < size ) { Time_t now = Time(); msecs = now < deadline ? deadline - now : 0; } } // Hay por lo menos size bytes libres, escribir nbytes = size; d = data; while ( size-- ) { *p->tail++ = *d++; if ( p->tail == p->end ) p->tail = p->buf; } // Despertar eventuales lectores bloqueados if ( !p->avail ) BroadcastCondition(p->cond_get); p->avail += nbytes; // Retornar cantidad de bytes escritos LeaveMonitor(p->monitor); return nbytes; }
unsigned GetPipeTimed(Pipe_t *p, void *data, unsigned size, unsigned msecs) { unsigned i, nbytes; char *d; if ( !size || !EnterMonitor(p->monitor) ) return 0; // Si hay un timeout finito, calcular deadline. Time_t deadline = (msecs && msecs != FOREVER) ? Time() + msecs : 0; // Bloquearse si el pipe está vacío while ( !p->avail ) { // Desistir si es condicional, si no esperar if ( !msecs || !WaitConditionTimed(p->cond_get, msecs) ) { LeaveMonitor(p->monitor); return 0; } // Si hay que seguir esperando con deadline, recalcular timeout if ( deadline && !p->avail ) { Time_t now = Time(); msecs = now < deadline ? deadline - now : 0; } } // Leer lo que se pueda for ( nbytes = min(size, p->avail), d = data, i = 0 ; i < nbytes ; i++ ) { *d++ = *p->head++; if ( p->head == p->end ) p->head = p->buf; } // Despertar eventuales escritores bloqueados BroadcastCondition(p->cond_put); p->avail -= nbytes; // Retornar cantidad de bytes leídos LeaveMonitor(p->monitor); return nbytes; }
void consumer(void *arg) { char *name = arg; while ( true ) { EnterMonitor(mon); while ( !key ) WaitCondition(cond); printf("%s: key %c\n", name, key); key = 0; SignalCondition(cond); LeaveMonitor(mon); } }
bool WaitConditionTimed(Condition_t *cond, unsigned msecs) { bool success; Monitor_t *mon = cond->monitor; if ( mon->owner != mt_curr_task ) Panic("WaitConditionTimed %s: la tarea no posee el monitor %s", GetName(cond), GetName(cond->monitor)); Atomic(); LeaveMonitor(mon); success = WaitQueueTimed(&cond->queue, msecs); while ( !EnterMonitor(mon) ) // Hay que volver a tomar el monitor si o si ; Unatomic(); return success; }
int main(void) { mon = CreateMonitor("dos"); cond = CreateCondition("key", mon); Ready(CreateTask(consumer, 2000, "consumer", "consumer", DEFAULT_PRIO)); while ( true ) { EnterMonitor(mon); while ( key ) WaitCondition(cond); key = getch(); if ( key == 'S' || key == 's' ) return 0; SignalCondition(cond); LeaveMonitor(mon); } }