static VALUE thread_spec_rb_thread_wait_for(VALUE self, VALUE s, VALUE ms) { struct timeval tv; tv.tv_sec = NUM2INT(s); tv.tv_usec = NUM2INT(ms); rb_thread_wait_for(tv); return Qnil; }
static VALUE thread_wait_for(VALUE time) { const struct timeval *t = (struct timeval *)time; rb_thread_wait_for(*t); return Qnil; }
static VALUE blocking_function_execute(blocking_region_arg_t *arg) { oci8_svcctx_t *svcctx = arg->svcctx; void *(*func)(void *) = arg->func; void *data = arg->data; struct timeval tv; sword rv; tv.tv_sec = 0; tv.tv_usec = 10000; svcctx->executing_thread = rb_thread_current(); while ((rv = (sword)(VALUE)func(data)) == OCI_STILL_EXECUTING) { rb_thread_wait_for(tv); if (tv.tv_usec < 500000) tv.tv_usec <<= 1; } if (rv == OCI_ERROR) { if (oci8_get_error_code(oci8_errhp) == 1013) { OCIReset(svcctx->base.hp.ptr, oci8_errhp); svcctx->executing_thread = Qnil; rb_raise(eOCIBreak, "Canceled by user request."); } } svcctx->executing_thread = Qnil; return rv; }
/* Sits on the queue, deals with new connections*/ VALUE mtserver_fetcher_thread(VALUE self) { struct timeval delay,s_delay; int loops=80; VALUE socket; VALUE sockets=rb_iv_get(self,"@sockets"); delay.tv_usec=250000; s_delay.tv_usec=500; mtserver_avail_add(self); ++RMTServer(self)->workers; while (loops>0) { socket=rb_ary_shift(sockets); if (socket!=Qnil) { mtserver_avail_dec(self); if (rb_iv_get(self,"@ssl")==Qnil) { rb_funcall(self,rb_intern("_serve"),1,socket); } else { rb_funcall(self,rb_intern("_servessl"),1,socket); } mtserver_avail_add(self); } else { if (RMTServer(self)->avail>1) { rb_thread_wait_for(delay); --loops; } else { rb_thread_wait_for(s_delay); } } } mtserver_avail_dec(self); --RMTServer(self)->workers; // printf("-Thread\n"); return Qtrue; }
static gboolean idle(gpointer data) { struct timeval wait; wait.tv_sec = 0; wait.tv_usec = 10000; /* 10ms */ CHECK_INTS; if (!rb_thread_critical) rb_thread_wait_for(wait); return TRUE; }
int rb_thread_select(int max, fd_set * read, fd_set * write, fd_set * except, struct timeval *timeout) { if (!read && !write && !except) { if (!timeout) { rb_thread_sleep_forever(); return 0; } rb_thread_wait_for(*timeout); return 0; } else { return do_select(max, read, write, except, timeout); } }
// int msgctl(int msqid, int cmd, struct msqid_ds *buf); // http://man7.org/linux/man-pages/man2/msgctl.2.html // // Controls the queue with IPC_SET, IPC_INFO and IPC_RMID via msgctl(2). When no // argument is passed, it'll return the information about the queue from // IPC_INFO. // // TODO: IPC_SET is currently not supported. static VALUE sysvmq_stats(int argc, VALUE *argv, VALUE self) { struct msqid_ds info; VALUE info_hash; VALUE cmd; sysvmq_t* sysv; // Optional argument handling if (argc > 1) { rb_raise(rb_eArgError, "Wrong number of arguments (0..1)"); } // Default to IPC_STAT cmd = argc == 1 ? argv[0] : INT2FIX(IPC_STAT); TypedData_Get_Struct(self, sysvmq_t, &sysvmq_type, sysv); // TODO: Does FIX2INT actually perform this check already? Check_Type(cmd, T_FIXNUM); while (msgctl(sysv->id, FIX2INT(cmd), &info) < 0) { if (errno == EINTR) { rb_thread_wait_for(polling_interval); continue; } rb_sys_fail("Failed executing msgctl(2) command."); } // Map values from struct to a hash // TODO: Add all the fields // TODO: They are probably not ints.. info_hash = rb_hash_new(); rb_hash_aset(info_hash, ID2SYM(rb_intern("count")), INT2FIX(info.msg_qnum)); rb_hash_aset(info_hash, ID2SYM(rb_intern("maximum_size")), INT2FIX(info.msg_qbytes)); // TODO: Can probably make a better checker here for whether the struct // actually has the member. // TODO: BSD support? #ifdef __linux__ rb_hash_aset(info_hash, ID2SYM(rb_intern("size")), INT2FIX(info.__msg_cbytes)); #elif __APPLE__ rb_hash_aset(info_hash, ID2SYM(rb_intern("size")), INT2FIX(info.msg_cbytes)); #endif return info_hash; }
// int msgget(key_t key, int msgflg); // http://man7.org/linux/man-pages/man2/msgget.2.html // // Instead of calling `msgget` method directly to get the `msgid` (the return // value of `msgget`) from Rubyland and pass it around, it's stored internally // in a struct only directly accessible from C-land. It's passed to all the // other calls that require a `msgid`, for convienence and to share the buffer. VALUE sysvmq_initialize(VALUE self, VALUE key, VALUE buffer_size, VALUE flags) { sysvmq_t* sysv; size_t msgbuf_size; // TODO: Also support string keys, so you can pass '0xDEADC0DE' Check_Type(key, T_FIXNUM); Check_Type(flags, T_FIXNUM); Check_Type(buffer_size, T_FIXNUM); TypedData_Get_Struct(self, sysvmq_t, &sysvmq_type, sysv); // (key_t) is a 32-bit integer (int). It's defined as `int` (at least on OS X // and Linux). However, `FIX2INT()` (from Ruby) will complain if the key is // something in the range 2^31-2^32, because of the sign bit. We use UINT to // trick Ruby, so it won't complain. sysv->key = (key_t) FIX2UINT(key); while ((sysv->id = msgget(sysv->key, FIX2INT(flags))) < 0) { if (errno == EINTR) { rb_thread_wait_for(polling_interval); // TODO: Really necessary here? continue; } rb_sys_fail("Failed opening the message queue."); } // Allocate the msgbuf buffer once for the instance, to not allocate a buffer // for each message sent. This makes SysVMQ not thread-safe (requiring a // buffer for each thread), but is a reasonable trade-off for now for the // performance. sysv->buffer_size = (size_t) FIX2LONG(buffer_size + 1); msgbuf_size = sysv->buffer_size * sizeof(char) + sizeof(long); // Note that this is a zero-length array, so we size the struct to size of the // header (long, the mtype) and then the rest of the space for message buffer. sysv->msgbuf = (sysvmq_msgbuf_t*) xmalloc(msgbuf_size); return self; }
static VALUE mutex_sleep(VALUE self, SEL sel, int argc, VALUE *argv) { VALUE timeout; rb_scan_args(argc, argv, "01", &timeout); rb_mutex_unlock(self, 0); time_t beg, end; beg = time(0); if (timeout == Qnil) { rb_thread_sleep_forever(); } else { struct timeval t = rb_time_interval(timeout); rb_thread_wait_for(t); } end = time(0) - beg; return INT2FIX(end); }
/* This thread constantly monitors the connection queue, launching new fetcher threads as * needed */ VALUE mtserver_monitor_thread(VALUE self) { struct timeval delay; VALUE sockets=rb_iv_get(self,"@sockets"); delay.tv_usec=1000000; while (1) { if (mtserver_get_avail(self)*2<RARRAY(sockets)->len) { if (RMTServer(self)->workers<FIX2INT(rb_iv_get(self,"@maxWorkers"))) { rb_thread_create(mtserver_fetcher_thread,(void *)self); } // printf("Add\n"); } rb_thread_wait_for(delay); } return Qtrue; }
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks) { int status; rb_blocking_function_t *func = connect_blocking; struct connect_arg arg; #if WAIT_IN_PROGRESS > 0 int wait_in_progress = -1; int sockerr; socklen_t sockerrlen; #endif arg.fd = fd; arg.sockaddr = sockaddr; arg.len = len; #if defined(SOCKS) && !defined(SOCKS5) if (socks) func = socks_connect_blocking; #endif for (;;) { status = (int)BLOCKING_REGION_FD(func, &arg); if (status < 0) { switch (errno) { case EINTR: #if defined(ERESTART) case ERESTART: #endif continue; case EAGAIN: #ifdef EINPROGRESS case EINPROGRESS: #endif #if WAIT_IN_PROGRESS > 0 sockerrlen = (socklen_t)sizeof(sockerr); status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen); if (status) break; if (sockerr) { status = -1; errno = sockerr; break; } #endif #ifdef EALREADY case EALREADY: #endif #if WAIT_IN_PROGRESS > 0 wait_in_progress = WAIT_IN_PROGRESS; #endif status = wait_connectable(fd); if (status) { break; } errno = 0; continue; #if WAIT_IN_PROGRESS > 0 case EINVAL: if (wait_in_progress-- > 0) { /* * connect() after EINPROGRESS returns EINVAL on * some platforms, need to check true error * status. */ sockerrlen = (socklen_t)sizeof(sockerr); status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen); if (!status && !sockerr) { struct timeval tv = {0, 100000}; rb_thread_wait_for(tv); continue; } status = -1; errno = sockerr; } break; #endif #ifdef EISCONN case EISCONN: status = 0; errno = 0; break; #endif default: break; } } return status; } }