static int readline_event() { CHECK_INTS; rb_thread_schedule(); return 0; }
static VALUE run_thread(VALUE thread) { thread = wake_thread(thread); if (RTEST(thread) && !rb_thread_critical) rb_thread_schedule(); return thread; }
static enum MqErrorE sEvent ( struct MqS * const context, MQ_PTR const data ) { rb_thread_schedule(); return MQ_OK; }
static VALUE asteroid_s_run(VALUE Self, VALUE Host, VALUE Port, VALUE Module){ char *host = StringValuePtr(Host); int port = FIX2INT(Port); epoll_fd = asteroid_poll_create(1024); if(epoll_fd == -1) runtime_error(); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(host); int s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP), c, one = 1; if(s == -1) runtime_error(); fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0) | O_NONBLOCK); setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); nosigpipe(s); if(bind(s, (struct sockaddr*)&addr, sizeof(addr)) != 0) runtime_error(); if(listen(s, MAX_CONNECTION) != 0) runtime_error(); if(rb_block_given_p()) rb_yield(Qnil); VALUE Class = rb_define_class_under(Asteroid, "Server", rb_cObject); rb_define_method(Class, "send_data", asteroid_server_send_data, 1); rb_define_method(Class, "write_and_close", asteroid_server_write_and_close, 0); rb_include_module(Class, Module); // Mac OS X, Fedora needs explicit rb_thread_schedule call. for(running = 1; running; rb_thread_schedule()){ socklen_t len = sizeof(addr); while((c = accept(s, (struct sockaddr*)&addr, &len)) != -1){ printf("A New client connected here\n"); fcntl(c, F_SETFL, fcntl(c, F_GETFL, 0) | O_NONBLOCK); asteroid_poll_event_t event; memset(&event, 0, sizeof(event)); if(asteroid_poll_add(epoll_fd, &event, c) == -1) runtime_error(); // instantiate server class which responds to client. VALUE Server = rb_class_new_instance(0, NULL, Class); rb_iv_set(Server, "@fd", rb_fix_new(c)); rb_hash_aset(clients, rb_fix_new(c), Server); if(rb_respond_to(Server, rb_intern("post_init"))){ rb_funcall(Server, rb_intern("post_init"), 0); } } if(dispatch() != 0) asteroid_s_stop(Asteroid); // You must call them to give a chance for ruby to handle system events. // CHECK_INTS; } rb_iterate(rb_each, clients, close_socket_proc, Qnil); rb_funcall(clients, rb_intern("clear"), 0); close(s); close(epoll_fd); return Qnil; }
static VALUE rb_condvar_broadcast(VALUE self) { ConditionVariable *condvar; Data_Get_Struct(self, ConditionVariable, condvar); thread_exclusive(wake_all, (VALUE)&condvar->waiting); rb_thread_schedule(); return self; }
static VALUE rb_condvar_broadcast(VALUE self) { ConditionVariable *condvar; Data_Get_Struct(self, ConditionVariable, condvar); //rb_thread_critical = 1; rb_ensure(wake_all, (VALUE)&condvar->waiting, set_critical, 0); rb_thread_schedule(); return self; }
static int readline_event() { #if BUSY_WAIT rb_thread_schedule(); #else fd_set rset; FD_ZERO(&rset); FD_SET(fileno(rl_instream), &rset); rb_thread_select(fileno(rl_instream) + 1, &rset, NULL, NULL, NULL); return 0; #endif }
/* Run the event loop, calling rb_thread_schedule every 10ms */ static void Coolio_Loop_ev_loop_oneshot(struct Coolio_Loop *loop_data) { struct ev_timer timer; struct timeval tv; /* Set up an ev_timer to unblock the loop every 10ms */ ev_timer_init(&timer, timer_callback, BLOCKING_INTERVAL, BLOCKING_INTERVAL); ev_timer_start(loop_data->ev_loop, &timer); /* Loop until we receive events */ while(!loop_data->events_received) { TRAP_BEG; RUN_LOOP(loop_data, EVLOOP_ONESHOT); TRAP_END; rb_thread_schedule(); } ev_timer_stop(loop_data->ev_loop, &timer); }
static VALUE asteroid_server_send_data(VALUE Self, VALUE Data){ VALUE Fd = rb_iv_get(Self, "@fd"); int fd = FIX2INT(Fd), remain = RSTRING(Data)->len, len, trial = 100; char *data = StringValuePtr(Data); while(remain){ len = send(fd, data, remain, MSG_DONTWAIT|MSG_NOSIGNAL); if(len == -1){ if(errno == EAGAIN && --trial){ rb_thread_schedule(); CHECK_INTS; }else{ if(rb_respond_to(Self, rb_intern("unbind"))){ rb_funcall(Self, rb_intern("unbind"), 0); } return Qnil; } }else{ remain -= len; data += len; } } return Qtrue; }
/** * call-seq: * Coolio::Loop.run_once -> nil * * Run the Coolio::Loop once, blocking until events are received. */ static VALUE Coolio_Loop_run_once(VALUE self) { VALUE nevents; if (Coolio_Loop_may_block_safely()) { struct Coolio_Loop *loop_data; Data_Get_Struct(self, struct Coolio_Loop, loop_data); assert(loop_data->ev_loop && !loop_data->events_received); Coolio_Loop_ev_loop_oneshot(loop_data); Coolio_Loop_dispatch_events(loop_data); nevents = INT2NUM(loop_data->events_received); loop_data->events_received = 0; } else { nevents = Coolio_Loop_run_nonblock(self); rb_thread_schedule(); } return nevents; }
static VALUE loop_run_poll(VALUE argp) { lp_arg *args = (lp_arg*)argp; rb_mt_loop *loop = args->loop; hrtime_t now, next_time; if (loop->events.count) { uint32_t i; args->fds = calloc(loop->events.count, sizeof(struct pollfd)); if (args->fds == NULL) { rb_raise(cb_eClientNoMemoryError, "failed to allocate memory for pollfd"); } for(i = 0; i < loop->events.count; i++) { rb_mt_socket_list *list = &loop->events.sockets[i]; args->fds[i].fd = list->socket; args->fds[i].events = (list->flags & LCB_READ_EVENT ? POLLIN : 0) | (list->flags & LCB_WRITE_EVENT ? POLLOUT : 0); } args->nfd = loop->events.count; } retry: next_time = timers_minimum(&loop->timers); if (next_time) { now = gethrtime(); args->ts = next_time <= now ? 0 : next_time - now; } else { args->ts = HRTIME_INFINITY; } #ifdef HAVE_RB_THREAD_BLOCKING_REGION rb_thread_blocking_region(loop_blocking_poll, args, RUBY_UBF_PROCESS, NULL); #else if (rb_thread_alone()) { TRAP_BEG; args->result = xpoll(args->fds, args->nfd, args->ts); if (args->result < 0) args->lerrno = errno; TRAP_END; } else { /* 5 millisecond pause */ hrtime_t mini_pause = 5000000; int exact = 0; if (args->ts != HRTIME_INFINITY && args->ts < mini_pause) { mini_pause = args->ts; exact = 1; } TRAP_BEG; args->result = xpoll(args->fds, args->nfd, mini_pause); if (args->result < 0) args->lerrno = errno; TRAP_END; if (args->result == 0 && !exact) { args->result = -1; args->lerrno = EINTR; } } #endif if (args->result < 0) { errno = args->lerrno; switch (errno) { case EINTR: #ifdef ERESTART case ERESTART: #endif #ifndef HAVE_RB_THREAD_BLOCKING_REGION rb_thread_schedule(); #endif goto retry; } rb_sys_fail("poll"); return Qnil; } if (next_time) { now = gethrtime(); } if (args->result > 0) { uint32_t cnt = args->result; uint32_t fd_n = 0, ev_n = 0; while (cnt && fd_n < args->nfd && ev_n < loop->events.count) { struct pollfd *res = args->fds + fd_n; rb_mt_socket_list *list = loop->events.sockets + ev_n; rb_mt_event *sock = list->first; /* if plugin used correctly, this checks are noop */ if (res->fd < list->socket) { fd_n++; continue; } else if (res->fd > list->socket) { ev_n++; continue; } if (res->revents) { short flags = ((res->revents & POLLIN_SET) ? LCB_READ_EVENT : 0) | ((res->revents & POLLOUT_SET) ? LCB_WRITE_EVENT : 0); cnt--; loop_enque_events(&loop->callbacks, sock, flags); } fd_n++; ev_n++; } callbacks_run(&loop->callbacks); } if (next_time) { timers_run(&loop->timers, now); } if (loop->events.count == 0 && loop->timers.count == 0) { loop->run = 0; } return Qnil; }
static VALUE thread_s_pass(VALUE klass, SEL sel) { rb_thread_schedule(); return Qnil; }
static int NIO_Selector_run(struct NIO_Selector *selector, VALUE timeout) { int result; selector->selecting = 1; #if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) || defined(HAVE_RB_THREAD_ALONE) /* Implement the optional timeout (if any) as a ev_timer */ if(timeout != Qnil) { /* It seems libev is not a fan of timers being zero, so fudge a little */ selector->timer.repeat = NUM2DBL(timeout) + 0.0001; ev_timer_again(selector->ev_loop, &selector->timer); } else { ev_timer_stop(selector->ev_loop, &selector->timer); } #else /* Store when we started the loop so we can calculate the timeout */ ev_tstamp started_at = ev_now(selector->ev_loop); #endif #if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) /* libev is patched to release the GIL when it makes its system call */ ev_loop(selector->ev_loop, EVLOOP_ONESHOT); #elif defined(HAVE_RB_THREAD_ALONE) /* If we're the only thread we can make a blocking system call */ if(rb_thread_alone()) { #else /* If we don't have rb_thread_alone() we can't block */ if(0) { #endif /* defined(HAVE_RB_THREAD_BLOCKING_REGION) */ #if !defined(HAVE_RB_THREAD_BLOCKING_REGION) && !defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) TRAP_BEG; ev_loop(selector->ev_loop, EVLOOP_ONESHOT); TRAP_END; } else { /* We need to busy wait as not to stall the green thread scheduler Ruby 1.8: just say no! :( */ ev_timer_init(&selector->timer, NIO_Selector_timeout_callback, BUSYWAIT_INTERVAL, BUSYWAIT_INTERVAL); ev_timer_start(selector->ev_loop, &selector->timer); /* Loop until we receive events */ while(selector->selecting && !selector->ready_count) { TRAP_BEG; ev_loop(selector->ev_loop, EVLOOP_ONESHOT); TRAP_END; /* Run the next green thread */ rb_thread_schedule(); /* Break if the timeout has elapsed */ if(timeout != Qnil && ev_now(selector->ev_loop) - started_at >= NUM2DBL(timeout)) break; } ev_timer_stop(selector->ev_loop, &selector->timer); } #endif /* defined(HAVE_RB_THREAD_BLOCKING_REGION) */ result = selector->ready_count; selector->selecting = selector->ready_count = 0; return result; } /* Wake the selector up from another thread */ static VALUE NIO_Selector_wakeup(VALUE self) { struct NIO_Selector *selector; Data_Get_Struct(self, struct NIO_Selector, selector); if(selector->closed) { rb_raise(rb_eIOError, "selector is closed"); } write(selector->wakeup_writer, "\0", 1); return Qnil; } /* Close the selector and free system resources */ static VALUE NIO_Selector_close(VALUE self) { VALUE args[1] = {self}; return NIO_Selector_synchronize(self, NIO_Selector_close_synchronized, args); }