예제 #1
0
static VALUE thread_spec_rb_thread_select(VALUE self, VALUE msec) {
  struct timeval tv;
  tv.tv_sec = 0;
  tv.tv_usec = NUM2INT(msec);
  rb_thread_select(0, NULL, NULL, NULL, &tv);
  return Qnil;
}
예제 #2
0
PGresult * do_postgres_cCommand_execute_async(VALUE self, VALUE connection, PGconn *db, VALUE query) {
  PGresult *response;
  char* str = StringValuePtr(query);

  while ((response = PQgetResult(db))) {
    PQclear(response);
  }

  struct timeval start;
  int retval;

  gettimeofday(&start, NULL);
  retval = PQsendQuery(db, str);

  if (!retval) {
    if (PQstatus(db) != CONNECTION_OK) {
      PQreset(db);

      if (PQstatus(db) == CONNECTION_OK) {
        retval = PQsendQuery(db, str);
      }
      else {
        do_postgres_full_connect(connection, db);
        retval = PQsendQuery(db, str);
      }
    }

    if (!retval) {
      rb_raise(eDO_ConnectionError, "%s", PQerrorMessage(db));
    }
  }

  int socket_fd = PQsocket(db);
  fd_set rset;

  while (1) {
    FD_ZERO(&rset);
    FD_SET(socket_fd, &rset);
    retval = rb_thread_select(socket_fd + 1, &rset, NULL, NULL, NULL);

    if (retval < 0) {
      rb_sys_fail(0);
    }

    if (retval == 0) {
      continue;
    }

    if (PQconsumeInput(db) == 0) {
      rb_raise(eDO_ConnectionError, "%s", PQerrorMessage(db));
    }

    if (PQisBusy(db) == 0) {
      break;
    }
  }

  data_objects_debug(connection, query, &start);
  return PQgetResult(db);
}
예제 #3
0
파일: fcgi.c 프로젝트: luongtran/po_tracker
static VALUE fcgi_s_accept(VALUE self)
{
  int status;
  FCGX_Request *req;
  fd_set readfds;

  req = ALLOC(FCGX_Request);

  status = FCGX_InitRequest(req,0,0);
  if (status != 0) {
    rb_raise(eFCGIError, "FCGX_Init() failed");
    return Qnil;
  }

  FD_ZERO(&readfds);
  FD_SET(req->listen_sock, &readfds);
  if (rb_thread_select(req->listen_sock+1, &readfds, NULL, NULL, NULL) < 1) {
    return Qnil;
  }

  status = FCGX_Accept_r(req);
  if (status >= 0) {
    fcgi_data *data;
    char      **env;
    VALUE     obj,key, value;
    char      *pkey,*pvalue;
    int       flags, fd;

    /* Unset NONBLOCKING */
    fd = ((FCGX_Request*) req)->ipcFd;
    flags = fcntl(fd, F_GETFL);

    if (flags & O_NONBLOCK) {
       fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
    }

    obj = Data_Make_Struct(self, fcgi_data, fcgi_mark, fcgi_free_req, data);
    data->req = req;
    data->in  = Data_Wrap_Struct(cFCGIStream, 0, 0, req->in);
    data->out = Data_Wrap_Struct(cFCGIStream, 0, 0, req->out);
    data->err = Data_Wrap_Struct(cFCGIStream, 0, 0, req->err);
    data->env = rb_hash_new();
    env = req->envp;
    for (; *env; env++) {
      int size = 0;
      pkey = *env;
      pvalue = pkey;
      while( *(pvalue++) != '=') size++;
      key   = rb_str_new(pkey, size);
      value = rb_str_new2(pvalue);
      OBJ_TAINT(key);
      OBJ_TAINT(value);
      rb_hash_aset(data->env, key, value);
    }

    return obj;
  } else {
    return Qnil;
  }
}
예제 #4
0
파일: curb_multi.c 프로젝트: wboton/curb
/*
 * call-seq:
 * multi = Curl::Multi.new
 * easy1 = Curl::Easy.new('url')
 * easy2 = Curl::Easy.new('url')
 *
 * multi.add(easy1)
 * multi.add(easy2)
 *
 * multi.perform do
 *  # while idle other code my execute here
 * end
 *
 * Run multi handles, looping selecting when data can be transfered
 */
static VALUE ruby_curl_multi_perform(VALUE self) {
  CURLMcode mcode;
  ruby_curl_multi *rbcm;
  int maxfd, rc;
  fd_set fdread, fdwrite, fdexcep;

  long timeout;
  struct timeval tv = {0, 0};

  Data_Get_Struct(self, ruby_curl_multi, rbcm);
  //rb_gc_mark(self);

  rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );

  while(rbcm->running) { 
    FD_ZERO(&fdread);
    FD_ZERO(&fdwrite);
    FD_ZERO(&fdexcep);

    /* load the fd sets from the multi handle */
    mcode = curl_multi_fdset(rbcm->handle, &fdread, &fdwrite, &fdexcep, &maxfd);
    if (mcode != CURLM_OK) {
      raise_curl_multi_error_exception(mcode);
    }

    /* get the curl suggested time out */
    mcode = curl_multi_timeout(rbcm->handle, &timeout);
    if (mcode != CURLM_OK) {
      raise_curl_multi_error_exception(mcode);
    }

    if (timeout == 0) { /* no delay */
      rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
      continue;
    }
    else if (timeout == -1) {
      timeout = 1; /* You must not wait too long 
                     (more than a few seconds perhaps) before 
                     you call curl_multi_perform() again */
    }

    if (rb_block_given_p()) {
      rb_yield(self);
    }
 
    tv.tv_sec = timeout / 1000;
    tv.tv_usec = (timeout * 1000) % 1000000;

    rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
    if (rc < 0) {
      rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno));
    }

    rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );

  }

  return Qnil;
}
예제 #5
0
static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
  struct nogvl_send_query_args args;
  fd_set fdset;
  int fd, retval;
  int async = 0;
  VALUE opts;
  VALUE rb_async;

  MYSQL * client;

  if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
    if ((rb_async = rb_hash_aref(opts, sym_async)) != Qnil) {
      async = rb_async == Qtrue ? 1 : 0;
    }
  }

  Check_Type(args.sql, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *conn_enc = rb_to_encoding(rb_iv_get(self, "@encoding"));
  // ensure the string is in the encoding the connection is expecting
  args.sql = rb_str_export_to_enc(args.sql, conn_enc);
#endif

  Data_Get_Struct(self, MYSQL, client);

  REQUIRE_OPEN_DB(client);

  args.mysql = client;
  if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
    return rb_raise_mysql2_error(client);
  }

  if (!async) {
    // the below code is largely from do_mysql
    // http://github.com/datamapper/do
    fd = client->net.fd;
    for(;;) {
      FD_ZERO(&fdset);
      FD_SET(fd, &fdset);

      retval = rb_thread_select(fd + 1, &fdset, NULL, NULL, NULL);

      if (retval < 0) {
          rb_sys_fail(0);
      }

      if (retval > 0) {
          break;
      }
    }

    return rb_mysql_client_async_result(self);
  } else {
    return Qnil;
  }
}
예제 #6
0
파일: em.cpp 프로젝트: btakita/eventmachine
int SelectData_t::_Select()
{
	#ifdef HAVE_TBR
	rb_thread_blocking_region (_SelectDataSelect, (void*)this, RB_UBF_DFL, 0);
	return nSockets;
	#endif

	#ifndef HAVE_TBR
	return rb_thread_select (maxsocket+1, &fdreads, &fdwrites, NULL, &tv);
	#endif
}
예제 #7
0
static VALUE thread_spec_rb_thread_select_fd(VALUE self, VALUE fd_num, VALUE msec) {
  int fd = NUM2INT(fd_num);

  fd_set read;
  FD_ZERO(&read);
  FD_SET(fd, &read);

  struct timeval tv = {0, NUM2INT(msec)};
  int n = rb_thread_select(fd + 1, &read, NULL, NULL, &tv);
  if(n == 1 && FD_ISSET(fd, &read)) return Qtrue;
  return Qfalse;
}
예제 #8
0
파일: client.c 프로젝트: JonathonMA/mysql2
static VALUE do_query(void *args) {
  struct async_query_args *async_args;
  struct timeval tv;
  struct timeval* tvp;
  long int sec;
  fd_set fdset;
  int retval;
  int fd_set_fd;
  VALUE read_timeout;

  async_args = (struct async_query_args *)args;
  read_timeout = rb_iv_get(async_args->self, "@read_timeout");

  tvp = NULL;
  if (!NIL_P(read_timeout)) {
    Check_Type(read_timeout, T_FIXNUM);
    tvp = &tv;
    sec = FIX2INT(read_timeout);
    // TODO: support partial seconds?
    // also, this check is here for sanity, we also check up in Ruby
    if (sec >= 0) {
      tvp->tv_sec = sec;
    } else {
      rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
    }
    tvp->tv_usec = 0;
  }

  fd_set_fd = async_args->fd;
  for(;;) {
    // the below code is largely from do_mysql
    // http://github.com/datamapper/do
    FD_ZERO(&fdset);
    FD_SET(fd_set_fd, &fdset);

    retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp);

    if (retval == 0) {
      rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
    }

    if (retval < 0) {
      rb_sys_fail(0);
    }

    if (retval > 0) {
      break;
    }
  }

  return Qnil;
}
예제 #9
0
static VALUE
wait_for_thread(void *data)
{
    struct BlockingThread* thr = (struct BlockingThread *) data;
    char c, res;
    fd_set rfds;

    FD_ZERO(&rfds);
    FD_SET(thr->rdfd, &rfds);
    rb_thread_select(thr->rdfd + 1, &rfds, NULL, NULL, NULL);
    read(thr->rdfd, &c, 1);
    return Qnil;
}
예제 #10
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
}
예제 #11
0
파일: do_mysql.c 프로젝트: dariocravero/do
MYSQL_RES *do_mysql_cCommand_execute_async(VALUE self, VALUE connection, MYSQL *db, VALUE query) {
  int retval;

  if ((retval = mysql_ping(db)) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
    do_mysql_full_connect(connection, db);
  }

  struct timeval start;
  const char *str = rb_str_ptr_readonly(query);
  long len = rb_str_len(query);

  gettimeofday(&start, NULL);
  retval = mysql_send_query(db, str, len);

  CHECK_AND_RAISE(retval, query);

  int socket_fd = db->net.fd;
  fd_set rset;

  while (1) {
    FD_ZERO(&rset);
    FD_SET(socket_fd, &rset);

    retval = rb_thread_select(socket_fd + 1, &rset, NULL, NULL, NULL);

    if (retval < 0) {
      rb_sys_fail(0);
    }

    if (retval == 0) {
      continue;
    }

    if (db->status == MYSQL_STATUS_READY) {
      break;
    }
  }

  retval = mysql_read_query_result(db);
  CHECK_AND_RAISE(retval, query);
  data_objects_debug(connection, query, &start);

  MYSQL_RES *result = mysql_store_result(db);

  if (!result) {
    CHECK_AND_RAISE(mysql_errno(db), query);
  }

  return result;
}
예제 #12
0
static gint 
rbglib_poll (GPollFD *fds,
            guint    nfds,
            gint     timeout)
{
    struct timeval tv;
    fd_set rset, wset, xset;
    GPollFD *f;
    int ready;
    int maxfd = 0;

    FD_ZERO (&rset);
    FD_ZERO (&wset);
    FD_ZERO (&xset);

    for (f = fds; f < &fds[nfds]; ++f) {
        if (f->fd >= 0)	{
            if (f->events & G_IO_IN)
                FD_SET (f->fd, &rset);
            if (f->events & G_IO_OUT)
                FD_SET (f->fd, &wset);
            if (f->events & G_IO_PRI)
                FD_SET (f->fd, &xset);
            if (f->fd > maxfd && (f->events & (G_IO_IN|G_IO_OUT|G_IO_PRI)))
                maxfd = f->fd;
        }
    }
    tv.tv_sec = timeout / 1000;
    tv.tv_usec = (timeout % 1000) * 1000;

    ready = rb_thread_select (maxfd + 1, &rset, &wset, &xset,
                              timeout == -1 ? NULL : &tv);
    if (ready > 0) {
        for (f = fds; f < &fds[nfds]; ++f) {
            f->revents = 0;
            if (f->fd >= 0) {
                if (FD_ISSET (f->fd, &rset))
                    f->revents |= G_IO_IN;
                if (FD_ISSET (f->fd, &wset))
                    f->revents |= G_IO_OUT;
                if (FD_ISSET (f->fd, &xset))
                    f->revents |= G_IO_PRI;
            }
        }
    }

    return ready;
}
예제 #13
0
static VALUE method_get_next_event(VALUE self) {
  char buf[64];
  zkrb_event_t *event ;
  int fd;
  fd_set rset;
  VALUE hash ;
  FETCH_DATA_PTR(self, zk);

  for (;;) {

    // we use the is_running(self) method here because it allows us to have a
    // ruby-land semaphore that we can also use in the java extension
    //
    if (!is_running(self)) {
/*      fprintf(stderr, "method_get_next_event: running is false, returning nil\n");*/
      return Qnil;  // this case for shutdown
    }

    event = zkrb_dequeue(zk->queue, 1);

    /* Wait for an event using rb_thread_select() on the queue's pipe */
    if (event == NULL) {
      fd = zk->queue->pipe_read;

      FD_ZERO(&rset);
      FD_SET(fd, &rset);

      if (rb_thread_select(fd + 1, &rset, NULL, NULL, NULL) == -1)
        rb_raise(rb_eRuntimeError, "select failed: %d", errno);

      if (read(fd, buf, sizeof(buf)) == -1)
        rb_raise(rb_eRuntimeError, "read failed: %d", errno);

      continue;
    }

    hash = zkrb_event_to_ruby(event);
    zkrb_event_free(event);
    return hash;
  }
}
예제 #14
0
static VALUE method_zkrb_iterate_event_loop(VALUE self) {
  FETCH_DATA_PTR(self, zk);

  fd_set rfds, wfds, efds;
  FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);

  int fd=0, interest=0, events=0, rc=0, maxfd=0;
  struct timeval tv;

  zookeeper_interest(zk->zh, &fd, &interest, &tv);

  if (fd != -1) {
    if (interest & ZOOKEEPER_READ) {
      FD_SET(fd, &rfds);
    } else {
      FD_CLR(fd, &rfds);
    }
    if (interest & ZOOKEEPER_WRITE) {
      FD_SET(fd, &wfds);
    } else {
      FD_CLR(fd, &wfds);
    }
  } else {
    fd = 0;
  }

  // add our self-pipe to the read set, allow us to wake up in case our attention is needed
  int pipe_r_fd = get_self_pipe_read_fd(self);

  FD_SET(pipe_r_fd, &rfds);

  maxfd = (pipe_r_fd > fd) ? pipe_r_fd : fd;

  rc = rb_thread_select(maxfd+1, &rfds, &wfds, &efds, &tv);

  if (rc > 0) {
    if (FD_ISSET(fd, &rfds)) {
      events |= ZOOKEEPER_READ;
    }
    if (FD_ISSET(fd, &wfds)) {
      events |= ZOOKEEPER_WRITE;
    }

    // we got woken up by the self-pipe
    if (FD_ISSET(pipe_r_fd, &rfds)) {
      // one event has awoken us, so we clear one event from the pipe
      char b[1];

      if (read(pipe_r_fd, b, 1) < 0) {
        rb_raise(rb_eRuntimeError, "read from pipe failed: %s", clean_errno());
      }
    }

    rc = zookeeper_process(zk->zh, events);
  }
  else if (rc == 0) {
    zkrb_debug("timed out waiting for descriptor to be ready");
  }
  else {
    log_err("select returned: %d", rc);
  }

  return INT2FIX(rc);
}
예제 #15
0
VALUE
nlh_handle_events()
{
  char buff[CONNECTOR_MAX_MSG_SIZE];
  struct nlmsghdr *hdr;
  struct proc_event *event;
  
  VALUE extra_data;
  
  fd_set fds;
  
  FD_ZERO(&fds);
  FD_SET(nl_sock, &fds);
    
  if (0 > rb_thread_select(nl_sock + 1, &fds, NULL, NULL, NULL)) {
    rb_raise(rb_eStandardError, strerror(errno));
  }
  
  /* If there were no events detected, return */
  if (! FD_ISSET(nl_sock, &fds)) {
    return INT2FIX(0);
  }
  
  /* if there are events, make calls */  
  if (-1 == recv(nl_sock, buff, sizeof(buff), 0)) {
    rb_raise(rb_eStandardError, strerror(errno));
  }
  
  hdr = (struct nlmsghdr *)buff;
  
  if (NLMSG_ERROR == hdr->nlmsg_type) {
    rb_raise(rb_eStandardError, strerror(errno));
  } else if (NLMSG_DONE == hdr->nlmsg_type) {    
    
    event = (struct proc_event *)((struct cn_msg *)NLMSG_DATA(hdr))->data;
    
    switch(event->what) {
      case PROC_EVENT_EXIT:
        if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.exit.process_pid))) {
          return INT2FIX(0);
        }
      
        extra_data = rb_hash_new();
        rb_hash_aset(extra_data, ID2SYM(rb_intern("pid")), INT2FIX(event->event_data.exit.process_pid));
        rb_hash_aset(extra_data, ID2SYM(rb_intern("exit_code")), INT2FIX(event->event_data.exit.exit_code));
        rb_hash_aset(extra_data, ID2SYM(rb_intern("exit_signal")), INT2FIX(event->event_data.exit.exit_signal));
        rb_hash_aset(extra_data, ID2SYM(rb_intern("thread_group_id")), INT2FIX(event->event_data.exit.process_tgid));

        rb_funcall(cEventHandler, m_call, 3, INT2FIX(event->event_data.exit.process_pid), ID2SYM(proc_exit), extra_data);
        return INT2FIX(1);
      
      case PROC_EVENT_FORK:
        if (Qnil == rb_funcall(cEventHandler, m_watching_pid, 1, INT2FIX(event->event_data.fork.parent_pid))) {
          return INT2FIX(0);
        }
        
        extra_data = rb_hash_new();
        rb_hash_aset(extra_data, rb_intern("parent_pid"), INT2FIX(event->event_data.fork.parent_pid));
        rb_hash_aset(extra_data, rb_intern("parent_thread_group_id"), INT2FIX(event->event_data.fork.parent_tgid));
        rb_hash_aset(extra_data, rb_intern("child_pid"), INT2FIX(event->event_data.fork.child_pid));
        rb_hash_aset(extra_data, rb_intern("child_thread_group_id"), INT2FIX(event->event_data.fork.child_tgid));
      
        rb_funcall(cEventHandler, m_call, 3, INT2FIX(event->event_data.fork.parent_pid), ID2SYM(proc_fork), extra_data);
        return INT2FIX(1);

      case PROC_EVENT_NONE:
      case PROC_EVENT_EXEC:
      case PROC_EVENT_UID:
      case PROC_EVENT_GID:
        break;
    }
  }
  
  return Qnil;
}
예제 #16
0
파일: client.c 프로젝트: heathd/mysql2
static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
    struct nogvl_send_query_args args;
    fd_set fdset;
    int fd, retval;
    int async = 0;
    VALUE opts, defaults, read_timeout;
    GET_CLIENT(self);

    REQUIRE_OPEN_DB(wrapper);
    args.mysql = wrapper->client;

    // see if this connection is still waiting on a result from a previous query
    if (wrapper->active == 0) {
        // mark this connection active
        wrapper->active = 1;
    } else {
        rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
    }

    defaults = rb_iv_get(self, "@query_options");
    if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
        opts = rb_funcall(defaults, intern_merge, 1, opts);
        rb_iv_set(self, "@query_options", opts);

        if (rb_hash_aref(opts, sym_async) == Qtrue) {
            async = 1;
        }
    } else {
        opts = defaults;
    }

    Check_Type(args.sql, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
    rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
    // ensure the string is in the encoding the connection is expecting
    args.sql = rb_str_export_to_enc(args.sql, conn_enc);
#endif

    if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
        // an error occurred, we're not active anymore
        MARK_CONN_INACTIVE(self);
        return rb_raise_mysql2_error(wrapper->client);
    }

    read_timeout = rb_iv_get(self, "@read_timeout");
    struct timeval tv;
    struct timeval* tvp = NULL;
    if (!NIL_P(read_timeout)) {
        Check_Type(read_timeout, T_FIXNUM);
        tvp = &tv;
        long int sec = FIX2INT(read_timeout);
        // TODO: support partial seconds?
        // also, this check is here for sanity, we also check up in Ruby
        if (sec >= 0) {
            tvp->tv_sec = sec;
        } else {
            rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %d", sec);
        }
        tvp->tv_usec = 0;
    }

    if (!async) {
        // the below code is largely from do_mysql
        // http://github.com/datamapper/do
        fd = wrapper->client->net.fd;
        for(;;) {
            FD_ZERO(&fdset);
            FD_SET(fd, &fdset);

            retval = rb_thread_select(fd + 1, &fdset, NULL, NULL, tvp);

            if (retval == 0) {
                rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
            }

            if (retval < 0) {
                rb_sys_fail(0);
            }

            if (retval > 0) {
                break;
            }
        }

        VALUE result = rb_mysql_client_async_result(self);

        return result;
    } else {
        return Qnil;
    }
}
예제 #17
0
/*
 * call-seq:
 * multi = Curl::Multi.new
 * easy1 = Curl::Easy.new('url')
 * easy2 = Curl::Easy.new('url')
 *
 * multi.add(easy1)
 * multi.add(easy2)
 *
 * multi.perform do
 *  # while idle other code my execute here
 * end
 *
 * Run multi handles, looping selecting when data can be transfered
 */
VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
  CURLMcode mcode;
  ruby_curl_multi *rbcm;
  int maxfd, rc;
  fd_set fdread, fdwrite, fdexcep;
#ifdef _WIN32
  fd_set crt_fdread, crt_fdwrite, crt_fdexcep;
#endif

  long timeout_milliseconds;
  struct timeval tv = {0, 0};
  VALUE block = Qnil;

  rb_scan_args(argc, argv, "0&", &block);

  Data_Get_Struct(self, ruby_curl_multi, rbcm);

  timeout_milliseconds = cCurlMutiDefaulttimeout;

  rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
 
  do {
    while (rbcm->running) {

#ifdef HAVE_CURL_MULTI_TIMEOUT
      /* get the curl suggested time out */
      mcode = curl_multi_timeout(rbcm->handle, &timeout_milliseconds);
      if (mcode != CURLM_OK) {
        raise_curl_multi_error_exception(mcode);
      }
#else
      /* libcurl doesn't have a timeout method defined, initialize to -1 we'll pick up the default later */
      timeout_milliseconds = -1;
#endif

      if (timeout_milliseconds == 0) { /* no delay */
        rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
        continue;
      }
      else if (timeout_milliseconds < 0) {
        timeout_milliseconds = cCurlMutiDefaulttimeout; /* libcurl doesn't know how long to wait, use a default timeout */
      }

      if (timeout_milliseconds > cCurlMutiDefaulttimeout) {
        timeout_milliseconds = cCurlMutiDefaulttimeout; /* buggy versions libcurl sometimes reports huge timeouts... let's cap it */
      }

      tv.tv_sec  = 0; /* never wait longer than 1 second */
      tv.tv_usec = (int)(timeout_milliseconds * 1000); /* XXX: int is the right type for OSX, what about linux? */

      if (timeout_milliseconds == 0) { /* no delay */
        rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
        continue;
      }

      if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self);  }

      FD_ZERO(&fdread);
      FD_ZERO(&fdwrite);
      FD_ZERO(&fdexcep);
      /* load the fd sets from the multi handle */
      mcode = curl_multi_fdset(rbcm->handle, &fdread, &fdwrite, &fdexcep, &maxfd);
      if (mcode != CURLM_OK) {
        raise_curl_multi_error_exception(mcode);
      }

#ifdef _WIN32
      create_crt_fd(&fdread, &crt_fdread);
      create_crt_fd(&fdwrite, &crt_fdwrite);
      create_crt_fd(&fdexcep, &crt_fdexcep);
#endif

      rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);

#ifdef _WIN32
      cleanup_crt_fd(&fdread, &crt_fdread);
      cleanup_crt_fd(&fdwrite, &crt_fdwrite);
      cleanup_crt_fd(&fdexcep, &crt_fdexcep);
#endif

      switch(rc) {
      case -1:
        rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno));
        break;
      case 0:
        rb_curl_multi_read_info( self, rbcm->handle );
        if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self);  }
      default: 
        rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
        break;
      }
    }
    rb_curl_multi_read_info( self, rbcm->handle );
    if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self);  }
  } while( rbcm->running );
    
  return Qtrue;
}
예제 #18
0
static VALUE thread_spec_rb_thread_select(VALUE self, VALUE msec) {
  struct timeval tv = {0, NUM2INT(msec)};
  rb_thread_select(0, NULL, NULL, NULL, &tv);
  return Qnil;
}
예제 #19
0
파일: client.c 프로젝트: leadtune/mysql2
static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
    struct nogvl_send_query_args args;
    fd_set fdset;
    int fd, retval;
    int async = 0;
    VALUE opts, defaults, read_timeout;
#ifdef HAVE_RUBY_ENCODING_H
    rb_encoding *conn_enc;
#endif
    struct timeval tv;
    struct timeval* tvp;
    long int sec;
    VALUE result;
    GET_CLIENT(self);

    REQUIRE_OPEN_DB(wrapper);
    args.mysql = wrapper->client;

    // see if this connection is still waiting on a result from a previous query
    if (wrapper->active == 0) {
        // mark this connection active
        wrapper->active = 1;
    } else {
        rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
    }

    defaults = rb_iv_get(self, "@query_options");
    if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
        opts = rb_funcall(defaults, intern_merge, 1, opts);
        rb_iv_set(self, "@query_options", opts);

        if (rb_hash_aref(opts, sym_async) == Qtrue) {
            async = 1;
        }
    } else {
        opts = defaults;
    }

    Check_Type(args.sql, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
    conn_enc = rb_to_encoding(wrapper->encoding);
    // ensure the string is in the encoding the connection is expecting
    args.sql = rb_str_export_to_enc(args.sql, conn_enc);
#endif

    if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
        // an error occurred, we're not active anymore
        MARK_CONN_INACTIVE(self);
        return rb_raise_mysql2_error(wrapper);
    }

    read_timeout = rb_iv_get(self, "@read_timeout");

    tvp = NULL;
    if (!NIL_P(read_timeout)) {
        Check_Type(read_timeout, T_FIXNUM);
        tvp = &tv;
        sec = FIX2INT(read_timeout);
        // TODO: support partial seconds?
        // also, this check is here for sanity, we also check up in Ruby
        if (sec >= 0) {
            tvp->tv_sec = sec;
        } else {
            rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
        }
        tvp->tv_usec = 0;
    }

    if (!async) {
        // the below code is largely from do_mysql
        // http://github.com/datamapper/do
        fd = wrapper->client->net.fd;
        for(;;) {
            int fd_set_fd = fd;

#if defined(_WIN32) && !defined(HAVE_RB_THREAD_BLOCKING_REGION)
            WSAPROTOCOL_INFO wsa_pi;
            // dupicate the SOCKET from libmysql
            int r = WSADuplicateSocket(fd, GetCurrentProcessId(), &wsa_pi);
            SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
            // create the CRT fd so ruby can get back to the SOCKET
            fd_set_fd = _open_osfhandle(s, O_RDWR|O_BINARY);
#endif

            FD_ZERO(&fdset);
            FD_SET(fd_set_fd, &fdset);

            retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp);

#if defined(_WIN32) && !defined(HAVE_RB_THREAD_BLOCKING_REGION)
            // cleanup the CRT fd
            _close(fd_set_fd);
            // cleanup the duplicated SOCKET
            closesocket(s);
#endif

            if (retval == 0) {
                rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
            }

            if (retval < 0) {
                rb_sys_fail(0);
            }

            if (retval > 0) {
                break;
            }
        }

        result = rb_mysql_client_async_result(self);

        return result;
    } else {
        return Qnil;
    }
}
예제 #20
0
/*
 * call-seq:
 * multi = Curl::Multi.new
 * easy1 = Curl::Easy.new('url')
 * easy2 = Curl::Easy.new('url')
 *
 * multi.add(easy1)
 * multi.add(easy2)
 *
 * multi.perform do
 *  # while idle other code my execute here
 * end
 *
 * Run multi handles, looping selecting when data can be transfered
 */
VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
  CURLMcode mcode;
  ruby_curl_multi *rbcm;
  int maxfd, rc;
  fd_set fdread, fdwrite, fdexcep;

  long timeout_milliseconds;
  struct timeval tv = {0, 0};
  VALUE block = Qnil;

  rb_scan_args(argc, argv, "0&", &block);

  Data_Get_Struct(self, ruby_curl_multi, rbcm);

  rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );

  while(rbcm->running) {
    FD_ZERO(&fdread);
    FD_ZERO(&fdwrite);
    FD_ZERO(&fdexcep);

    /* load the fd sets from the multi handle */
    mcode = curl_multi_fdset(rbcm->handle, &fdread, &fdwrite, &fdexcep, &maxfd);
    if (mcode != CURLM_OK) {
      raise_curl_multi_error_exception(mcode);
    }

#ifdef HAVE_CURL_MULTI_TIMEOUT
    /* get the curl suggested time out */
    mcode = curl_multi_timeout(rbcm->handle, &timeout_milliseconds);
    if (mcode != CURLM_OK) {
      raise_curl_multi_error_exception(mcode);
    }
#else
    /* libcurl doesn't have a timeout method defined... make a wild guess */
    timeout_milliseconds = -1;
#endif
    //printf("libcurl says wait: %ld ms or %ld s\n", timeout_milliseconds, timeout_milliseconds/1000);

    if (timeout_milliseconds == 0) { /* no delay */
      rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
      continue;
    }
    else if(timeout_milliseconds < 0) {
      timeout_milliseconds = 500; /* wait half a second, libcurl doesn't know how long to wait */
    }
#ifdef __APPLE_CC__
    if(timeout_milliseconds > 1000) {
      timeout_milliseconds = 1000; /* apple libcurl sometimes reports huge timeouts... let's cap it */
    }
#endif

    tv.tv_sec = timeout_milliseconds / 1000; // convert milliseconds to seconds
    tv.tv_usec = (timeout_milliseconds % 1000) * 1000; // get the remainder of milliseconds and convert to micro seconds

    rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
    switch(rc) {
    case -1:
      rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno));
      break;
    case 0:
      if (block != Qnil) {
        rb_funcall(block, rb_intern("call"), 1, self); 
      }
//      if (rb_block_given_p()) {
//        rb_yield(self);
//      }
    default: 
      rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
      break;
    }

  }

  return Qtrue;
}