int s_poll_wait(s_poll_set *fds, int timeout) { CONTEXT *ctx; /* current context */ static CONTEXT *to_free=NULL; /* delayed memory deallocation */ /* remove the current context from ready queue */ ctx=ready_head; ready_head=ready_head->next; if(!ready_head) /* the queue is empty */ ready_tail=NULL; if(fds) { /* something to wait for -> swap the context */ ctx->fds=fds; /* set file descriptors to wait for */ ctx->finish=timeout<0 ? -1 : time(NULL)+timeout; /* move (append) the current context to the waiting queue */ ctx->next=NULL; if(waiting_tail) waiting_tail->next=ctx; waiting_tail=ctx; if(!waiting_head) waiting_head=ctx; while(!ready_head) /* no context ready */ scan_waiting_queue(); if(ctx->id!=ready_head->id) { s_log(LOG_DEBUG, "Context swap: %ld -> %ld", ctx->id, ready_head->id); swapcontext(&ctx->ctx, &ready_head->ctx); s_log(LOG_DEBUG, "Current context: %ld", ready_head->id); if(to_free) { s_log(LOG_DEBUG, "Releasing context %ld", to_free->id); free(to_free); to_free=NULL; } } return ready_head->ready; } else { /* nothing to wait for -> drop the context */ /* it's illegal to deallocate the stack of the current context */ if(to_free) { s_log(LOG_DEBUG, "Releasing context %ld", to_free->id); free(to_free); } to_free=ctx; while(!ready_head) /* no context ready */ scan_waiting_queue(); s_log(LOG_DEBUG, "Context set: %ld (dropped) -> %ld", ctx->id, ready_head->id); setcontext(&ready_head->ctx); ioerror("setcontext"); /* should not ever happen */ return 0; } }
int s_poll_wait(s_poll_set *fds, int sec, int msec) { CONTEXT *context; /* current context */ static CONTEXT *to_free=NULL; /* delayed memory deallocation */ /* FIXME: msec parameter is currently ignored with UCONTEXT threads */ (void)msec; /* skip warning about unused parameter */ /* remove the current context from ready queue */ context=ready_head; ready_head=ready_head->next; if(!ready_head) /* the queue is empty */ ready_tail=NULL; /* it it safe to s_log() after new ready_head is set */ /* it's illegal to deallocate the stack of the current context */ if(to_free) { /* a delayed deallocation is scheduled */ #ifdef DEBUG_UCONTEXT s_log(LOG_DEBUG, "Releasing context %ld", to_free->id); #endif str_free(to_free->stack); str_free(to_free); to_free=NULL; } /* manage the current thread */ if(fds) { /* something to wait for -> swap the context */ context->fds=fds; /* set file descriptors to wait for */ context->finish=sec<0 ? -1 : time(NULL)+sec; /* append the current context to the waiting queue */ context->next=NULL; if(waiting_tail) waiting_tail->next=context; waiting_tail=context; if(!waiting_head) waiting_head=context; } else { /* nothing to wait for -> drop the context */ to_free=context; /* schedule for delayed deallocation */ } while(!ready_head) /* wait until there is a thread to switch to */ scan_waiting_queue(); /* switch threads */ if(fds) { /* swap the current context */ if(context->id!=ready_head->id) { #ifdef DEBUG_UCONTEXT s_log(LOG_DEBUG, "Context swap: %ld -> %ld", context->id, ready_head->id); #endif swapcontext(&context->context, &ready_head->context); #ifdef DEBUG_UCONTEXT s_log(LOG_DEBUG, "Current context: %ld", ready_head->id); #endif } return ready_head->ready; } else { /* drop the current context */ #ifdef DEBUG_UCONTEXT s_log(LOG_DEBUG, "Context set: %ld (dropped) -> %ld", context->id, ready_head->id); #endif setcontext(&ready_head->context); ioerror("setcontext"); /* should not ever happen */ return 0; } }