Ejemplo n.º 1
0
static VALUE _send(int sflags, int argc, VALUE *argv, VALUE self)
{
	struct posix_mq *mq = get(self, 1);
	struct rw_args x;
	VALUE buffer, prio, timeout;
	struct timespec expire;

	rb_scan_args(argc, argv, "12", &buffer, &prio, &timeout);

	setup_send_buffer(&x, buffer);
	x.des = mq->des;
	x.timeout = convert_timeout(&expire, timeout);
	x.msg_prio = NIL_P(prio) ? 0 : NUM2UINT(prio);

retry:
	WITHOUT_GVL(xsend, &x, RUBY_UBF_IO, 0);
	if (x.retval < 0) {
		if (errno == EINTR)
			goto retry;
		if (errno == EAGAIN && (sflags & PMQ_TRY))
			return Qfalse;
		rb_sys_fail("mq_send");
	}

	return Qtrue;
}
Ejemplo n.º 2
0
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
// http://man7.org/linux/man-pages/man2/msgsnd.2.html
//
// Receive a message from the message queue.
VALUE
sysvmq_receive(int argc, VALUE *argv, VALUE self)
{
  VALUE type  = INT2FIX(0);
  VALUE flags = INT2FIX(0);
  sysvmq_t* sysv;
  sysvmq_blocking_call_t blocking;

  if (argc > 2) {
    rb_raise(rb_eArgError, "Wrong number of arguments (0..2)");
  }

  if (argc >= 1) type  = argv[0];
  if (argc == 2) flags = argv[1];

  TypedData_Get_Struct(self, sysvmq_t, &sysvmq_type, sysv);

  Check_Type(type, T_FIXNUM);
  Check_Type(flags, T_FIXNUM);

  // Attach blocking call parameters to the struct passed to the blocking
  // function wrapper.
  blocking.flags  = FIX2INT(flags);
  blocking.type   = FIX2LONG(type);
  blocking.sysv   = sysv;
  // Initialize error so it's never a garbage value, if
  // `sysvmq_maybe_blocking_receive` was interrupted at a non-nice time.
  blocking.error  = UNINITIALIZED_ERROR;
  blocking.length = UNINITIALIZED_ERROR;

  if ((blocking.flags & IPC_NOWAIT) == IPC_NOWAIT) {
    while(sysvmq_maybe_blocking_receive(&blocking) == NULL && blocking.error < 0) {
      if (errno == EINTR) {
        continue;
      }

      rb_sys_fail("Failed recieving message from queue");
    }
  } else {
    // msgrcv(2) can block sending a message, if IPC_NOWAIT is not passed.
    // We unlock the GVL waiting for the call so other threads (e.g. signal
    // handling) can continue to work. Sets `length` on `blocking` with the size
    // of the message returned.
    while (WITHOUT_GVL(sysvmq_maybe_blocking_receive, &blocking, RUBY_UBF_IO, NULL) == NULL
            && blocking.error < 0) {
      if (errno == EINTR || blocking.error == UNINITIALIZED_ERROR) {
        continue;
      }

      rb_sys_fail("Failed receiving message from queue");
    }
  }

  // Guard it..
  assert(blocking.length != UNINITIALIZED_ERROR);

  // Reencode with default external encoding
  return rb_str_new(sysv->msgbuf->mtext, blocking.length);
}
Ejemplo n.º 3
0
static VALUE
instrumenter_start(VALUE self) {
  sky_instrumenter_t* instrumenter;

  My_Struct(instrumenter, sky_instrumenter_t, no_instrumenter_msg);

  return (VALUE) WITHOUT_GVL(instrumenter_start_nogvl, instrumenter);
}
Ejemplo n.º 4
0
static VALUE _receive(int rflags, int argc, VALUE *argv, VALUE self)
{
	struct posix_mq *mq = get(self, 1);
	struct rw_args x;
	VALUE buffer, timeout;
	struct timespec expire;

	if (mq->attr.mq_msgsize < 0) {
		if (mq_getattr(mq->des, &mq->attr) < 0)
			rb_sys_fail("mq_getattr");
	}

	rb_scan_args(argc, argv, "02", &buffer, &timeout);
	x.timeout = convert_timeout(&expire, timeout);

	if (NIL_P(buffer)) {
		buffer = rb_str_new(0, mq->attr.mq_msgsize);
	} else {
		StringValue(buffer);
		rb_str_modify(buffer);
		rb_str_resize(buffer, mq->attr.mq_msgsize);
	}
	OBJ_TAINT(buffer);
	x.msg_ptr = RSTRING_PTR(buffer);
	x.msg_len = (size_t)mq->attr.mq_msgsize;
	x.des = mq->des;

retry:
	WITHOUT_GVL(xrecv, &x, RUBY_UBF_IO, 0);
	if (x.received < 0) {
		if (errno == EINTR)
			goto retry;
		if (errno == EAGAIN && (rflags & PMQ_TRY))
			return Qnil;
		rb_sys_fail("mq_receive");
	}

	rb_str_set_len(buffer, x.received);

	if (rflags & PMQ_WANTARRAY)
		return rb_ary_new3(2, buffer, UINT2NUM(x.msg_prio));
	return buffer;
}
Ejemplo n.º 5
0
/*
 * call-seq:
 *	mq << string	=> mq
 *
 * Inserts the given +string+ into the message queue with a
 * default priority of 0 and no timeout.
 *
 * Returns itself so its calls may be chained.  This use is only
 * recommended only for users who expect blocking behavior from
 * the queue.
 */
static VALUE send0(VALUE self, VALUE buffer)
{
	struct posix_mq *mq = get(self, 1);
	struct rw_args x;

	setup_send_buffer(&x, buffer);
	x.des = mq->des;
	x.timeout = NULL;
	x.msg_prio = 0;

retry:
	WITHOUT_GVL(xsend, &x, RUBY_UBF_IO, 0);
	if (x.retval < 0) {
		if (errno == EINTR)
			goto retry;
		rb_sys_fail("mq_send");
	}

	return self;
}
Ejemplo n.º 6
0
void *
acquire_semaphore_without_gvl(void *p)
{
  WITHOUT_GVL(acquire_semaphore, p, RUBY_UBF_IO, NULL);
  return NULL;
}
Ejemplo n.º 7
0
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// http://man7.org/linux/man-pages/man2/msgsnd.2.html
//
// Sends a message to the message queue.
VALUE
sysvmq_send(int argc, VALUE *argv, VALUE self)
{
  VALUE message;
  VALUE priority = INT2FIX(1);
  VALUE flags = INT2FIX(0);
  sysvmq_blocking_call_t blocking;
  sysvmq_t* sysv;

  if (argc > 3 || argc == 0) {
    rb_raise(rb_eArgError, "Wrong number of arguments (1..3)");
  }

  message  = argv[0];
  if (argc >= 2) priority = argv[1];
  if (argc == 3) flags    = argv[2];

  TypedData_Get_Struct(self, sysvmq_t, &sysvmq_type, sysv);

  Check_Type(flags,    T_FIXNUM);
  Check_Type(priority, T_FIXNUM);
  // TODO: Call to_s on message if it responds to

  // Attach blocking call parameters to the struct passed to the blocking
  // function wrapper.
  blocking.flags = FIX2INT(flags);
  blocking.size  = RSTRING_LEN(message);
  blocking.sysv  = sysv;
  // See msgrcv(2) wrapper
  blocking.error  = UNINITIALIZED_ERROR;
  blocking.length = UNINITIALIZED_ERROR;

  // The buffer can be obtained from `sysvmq_maybe_blocking_send`, instead of
  // passing it, set it directly on the instance struct.
  sysv->msgbuf->mtype = FIX2INT(priority);

  if (blocking.size > sysv->buffer_size) {
    rb_raise(rb_eArgError, "Size of message is bigger than buffer size.");
  }

  // TODO: Can a string copy be avoided?
  memcpy(sysv->msgbuf->mtext, RSTRING_PTR(message), blocking.size);

  // Non-blocking call, skip the expensive GVL release/acquire
  if ((blocking.flags & IPC_NOWAIT) == IPC_NOWAIT) {
    while(sysvmq_maybe_blocking_send(&blocking) == NULL && blocking.error < 0) {
      if (errno == EINTR) {
        continue;
      }

      rb_sys_fail("Failed sending message to queue");
    }
  } else {
    // msgsnd(2) can block waiting for a message, if IPC_NOWAIT is not passed.
    // We unlock the GVL waiting for the call so other threads (e.g. signal
    // handling) can continue to work.
    while (WITHOUT_GVL(sysvmq_maybe_blocking_send, &blocking, RUBY_UBF_IO, NULL) == NULL
            && blocking.error < 0) {
      if (errno == EINTR || blocking.error == UNINITIALIZED_ERROR) {
        continue;
      }

      rb_sys_fail("Failed sending message to queue");
    }
  }

  return message;
}