Пример #1
0
static int
readline_event()
{
    CHECK_INTS;
    rb_thread_schedule();
    return 0;
}
Пример #2
0
static VALUE
run_thread(VALUE thread)
{
    thread = wake_thread(thread);
    if (RTEST(thread) && !rb_thread_critical)
	rb_thread_schedule();
    return thread;
}
Пример #3
0
static enum MqErrorE sEvent (
  struct MqS * const context,
  MQ_PTR const data
)
{
  rb_thread_schedule();
  return MQ_OK;
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
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
}
Пример #8
0
/* 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);
}
Пример #9
0
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;
}
Пример #10
0
/**
 *  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;
}
Пример #12
0
static VALUE
thread_s_pass(VALUE klass, SEL sel)
{
    rb_thread_schedule();
    return Qnil;
}
Пример #13
0
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);
}