Пример #1
0
/* Watch for a change in connectivity state.

   Once the channel connectivity state is different from the last observed
   state, tag will be enqueued on cq with success=1

   If deadline expires BEFORE the state is changed, tag will be enqueued on
   the completion queue with success=0 */
static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self,
                                                      VALUE last_state,
                                                      VALUE cqueue,
                                                      VALUE deadline,
                                                      VALUE tag) {
  grpc_rb_channel *wrapper = NULL;
  grpc_channel *ch = NULL;
  grpc_completion_queue *cq = NULL;

  cq = grpc_rb_get_wrapped_completion_queue(cqueue);
  TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
  ch = wrapper->wrapped;
  if (ch == NULL) {
    rb_raise(rb_eRuntimeError, "closed!");
    return Qnil;
  }
  grpc_channel_watch_connectivity_state(
      ch,
      (grpc_connectivity_state)NUM2LONG(last_state),
      grpc_rb_time_timeval(deadline, /* absolute time */ 0),
      cq,
      ROBJECT(tag));

  return Qnil;
}
Пример #2
0
/* Wait until the channel's connectivity state becomes different from
 * "last_state", or "deadline" expires.
 * Returns true if the channel's connectivity state becomes different
 * from "last_state" within "deadline".
 * Returns false if "deadline" expires before the channel's connectivity
 * state changes from "last_state".
 * */
static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self,
                                                      VALUE last_state,
                                                      VALUE deadline) {
  grpc_rb_channel* wrapper = NULL;
  watch_state_stack stack;
  void* op_success = 0;

  TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);

  if (wrapper->bg_wrapped == NULL) {
    rb_raise(rb_eRuntimeError, "closed!");
    return Qnil;
  }

  if (!FIXNUM_P(last_state)) {
    rb_raise(
        rb_eTypeError,
        "bad type for last_state. want a GRPC::Core::ChannelState constant");
    return Qnil;
  }

  stack.bg_wrapped = wrapper->bg_wrapped;
  stack.deadline = grpc_rb_time_timeval(deadline, 0),
  stack.last_state = NUM2LONG(last_state);

  op_success = rb_thread_call_without_gvl(
      wait_for_watch_state_op_complete_without_gvl, &stack,
      wait_for_watch_state_op_complete_unblocking_func, wrapper->bg_wrapped);

  return op_success ? Qtrue : Qfalse;
}
Пример #3
0
/* Create a call given a grpc_channel, in order to call method. The request
   is not sent until grpc_call_invoke is called. */
static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask,
                                         VALUE method, VALUE host,
                                         VALUE deadline) {
  VALUE res = Qnil;
  grpc_rb_channel *wrapper = NULL;
  grpc_call *call = NULL;
  grpc_call *parent_call = NULL;
  grpc_completion_queue *cq = NULL;
  int flags = GRPC_PROPAGATE_DEFAULTS;
  grpc_slice method_slice;
  grpc_slice host_slice;
  grpc_slice *host_slice_ptr = NULL;
  char *tmp_str = NULL;

  if (host != Qnil) {
    host_slice =
        grpc_slice_from_copied_buffer(RSTRING_PTR(host), RSTRING_LEN(host));
    host_slice_ptr = &host_slice;
  }
  if (mask != Qnil) {
    flags = NUM2UINT(mask);
  }
  if (parent != Qnil) {
    parent_call = grpc_rb_get_wrapped_call(parent);
  }

  cq = grpc_completion_queue_create_for_pluck(NULL);
  TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
  if (wrapper->bg_wrapped == NULL) {
    rb_raise(rb_eRuntimeError, "closed!");
    return Qnil;
  }

  method_slice =
      grpc_slice_from_copied_buffer(RSTRING_PTR(method), RSTRING_LEN(method));

  call = grpc_channel_create_call(wrapper->bg_wrapped->channel, parent_call,
                                  flags, cq, method_slice, host_slice_ptr,
                                  grpc_rb_time_timeval(deadline,
                                                       /* absolute time */ 0),
                                  NULL);

  if (call == NULL) {
    tmp_str = grpc_slice_to_c_string(method_slice);
    rb_raise(rb_eRuntimeError, "cannot create call with method %s", tmp_str);
    return Qnil;
  }

  grpc_slice_unref(method_slice);
  if (host_slice_ptr != NULL) {
    grpc_slice_unref(host_slice);
  }

  res = grpc_rb_wrap_call(call, cq);

  /* Make this channel an instance attribute of the call so that it is not GCed
   * before the call. */
  rb_ivar_set(res, id_channel, self);
  return res;
}
Пример #4
0
/* Create a call given a grpc_channel, in order to call method. The request
   is not sent until grpc_call_invoke is called. */
static VALUE grpc_rb_channel_create_call(VALUE self, VALUE method, VALUE host,
                                         VALUE deadline) {
  VALUE res = Qnil;
  grpc_rb_channel *wrapper = NULL;
  grpc_channel *ch = NULL;
  grpc_call *call = NULL;
  char *method_chars = StringValueCStr(method);
  char *host_chars = StringValueCStr(host);

  Data_Get_Struct(self, grpc_rb_channel, wrapper);
  ch = wrapper->wrapped;
  if (ch == NULL) {
    rb_raise(rb_eRuntimeError, "closed!");
  }

  call =
      grpc_channel_create_call_old(ch, method_chars, host_chars,
                                   grpc_rb_time_timeval(deadline,
                                                        /* absolute time */ 0));
  if (call == NULL) {
    rb_raise(rb_eRuntimeError, "cannot create call with method %s",
             method_chars);
  }
  res = grpc_rb_wrap_call(call);

  /* Make this channel an instance attribute of the call so that is is not GCed
   * before the call. */
  rb_ivar_set(res, id_channel, self);
  return res;
}
Пример #5
0
/* Blocks until the next event is available, and returns the event. */
static VALUE grpc_rb_completion_queue_next(VALUE self, VALUE timeout) {
  next_call_stack next_call;
  MEMZERO(&next_call, next_call_stack, 1);
  Data_Get_Struct(self, grpc_completion_queue, next_call.cq);
  next_call.timeout = grpc_rb_time_timeval(timeout, /* absolute time*/ 0);
  next_call.event = NULL;
  rb_thread_call_without_gvl(grpc_rb_completion_queue_next_no_gil,
                             (void *)&next_call, NULL, NULL);
  if (next_call.event == NULL) {
    return Qnil;
  }
  return grpc_rb_new_event(next_call.event);
}
Пример #6
0
/* Create a call given a grpc_channel, in order to call method. The request
   is not sent until grpc_call_invoke is called. */
static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue,
                                         VALUE parent, VALUE mask,
                                         VALUE method, VALUE host,
                                         VALUE deadline) {
  VALUE res = Qnil;
  grpc_rb_channel *wrapper = NULL;
  grpc_call *call = NULL;
  grpc_call *parent_call = NULL;
  grpc_channel *ch = NULL;
  grpc_completion_queue *cq = NULL;
  int flags = GRPC_PROPAGATE_DEFAULTS;
  char *method_chars = StringValueCStr(method);
  char *host_chars = NULL;
  if (host != Qnil) {
    host_chars = StringValueCStr(host);
  }
  if (mask != Qnil) {
    flags = NUM2UINT(mask);
  }
  if (parent != Qnil) {
    parent_call = grpc_rb_get_wrapped_call(parent);
  }

  cq = grpc_rb_get_wrapped_completion_queue(cqueue);
  TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
  ch = wrapper->wrapped;
  if (ch == NULL) {
    rb_raise(rb_eRuntimeError, "closed!");
    return Qnil;
  }

  call = grpc_channel_create_call(ch, parent_call, flags, cq, method_chars,
                                  host_chars, grpc_rb_time_timeval(
                                      deadline,
                                      /* absolute time */ 0), NULL);
  if (call == NULL) {
    rb_raise(rb_eRuntimeError, "cannot create call with method %s",
             method_chars);
    return Qnil;
  }
  res = grpc_rb_wrap_call(call);

  /* Make this channel an instance attribute of the call so that it is not GCed
   * before the call. */
  rb_ivar_set(res, id_channel, self);

  /* Make the completion queue an instance attribute of the call so that it is
   * not GCed before the call. */
  rb_ivar_set(res, id_cqueue, cqueue);
  return res;
}
Пример #7
0
/*
  call-seq:
    server = Server.new({'arg1': 'value1'})
    ... // do stuff with server
    ...
    ... // to shutdown the server
    server.destroy()

    ... // to shutdown the server with a timeout
    server.destroy(timeout)

  Destroys server instances. */
static VALUE grpc_rb_server_destroy(int argc, VALUE *argv, VALUE self) {
  VALUE timeout = Qnil;
  gpr_timespec deadline;
  grpc_rb_server *s = NULL;

  /* "01" == 0 mandatory args, 1 (timeout) is optional */
  rb_scan_args(argc, argv, "01", &timeout);
  TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
  if (TYPE(timeout) == T_NIL) {
    deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
  } else {
    deadline = grpc_rb_time_timeval(timeout, /* absolute time*/ 0);
  }

  destroy_server(s, deadline);

  return Qnil;
}
Пример #8
0
/* Blocks until the next event for given tag is available, and returns the
 * event. */
grpc_event grpc_rb_completion_queue_pluck_event(VALUE self, VALUE tag,
        VALUE timeout) {
    next_call_stack next_call;
    MEMZERO(&next_call, next_call_stack, 1);
    TypedData_Get_Struct(self, grpc_completion_queue,
                         &grpc_rb_completion_queue_data_type, next_call.cq);
    if (TYPE(timeout) == T_NIL) {
        next_call.timeout = gpr_inf_future;
    } else {
        next_call.timeout = grpc_rb_time_timeval(timeout, /* absolute time*/ 0);
    }
    if (TYPE(tag) == T_NIL) {
        next_call.tag = NULL;
    } else {
        next_call.tag = ROBJECT(tag);
    }
    next_call.event.type = GRPC_QUEUE_TIMEOUT;
    rb_thread_call_without_gvl(grpc_rb_completion_queue_pluck_no_gil,
                               (void *)&next_call, NULL, NULL);
    return next_call.event;
}
Пример #9
0
/* Blocks until the next event for given tag is available, and returns the
 * event. */
grpc_event grpc_rb_completion_queue_pluck_event(VALUE self, VALUE tag,
                                                VALUE timeout) {
  next_call_stack next_call;
  MEMZERO(&next_call, next_call_stack, 1);
  TypedData_Get_Struct(self, grpc_completion_queue,
                       &grpc_rb_completion_queue_data_type, next_call.cq);
  if (TYPE(timeout) == T_NIL) {
    next_call.timeout = gpr_inf_future(GPR_CLOCK_REALTIME);
  } else {
    next_call.timeout = grpc_rb_time_timeval(timeout, /* absolute time*/ 0);
  }
  if (TYPE(tag) == T_NIL) {
    next_call.tag = NULL;
  } else {
    next_call.tag = ROBJECT(tag);
  }
  next_call.event.type = GRPC_QUEUE_TIMEOUT;
  /* Loop until we finish a pluck without an interruption. The internal
     pluck function runs either until it is interrupted or it gets an
     event, or time runs out.

     The basic reason we need this relatively complicated construction is that
     we need to re-acquire the GVL when an interrupt comes in, so that the ruby
     interpreter can do what it needs to do with the interrupt. But we also need
     to get back to plucking when the interrupt has been handled. */
  do {
    next_call.interrupted = 0;
    rb_thread_call_without_gvl(grpc_rb_completion_queue_pluck_no_gil,
                               (void *)&next_call, unblock_func,
                               (void *)&next_call);
    /* If an interrupt prevented pluck from returning useful information, then
       any plucks that did complete must have timed out */
  } while (next_call.interrupted &&
           next_call.event.type == GRPC_QUEUE_TIMEOUT);
  return next_call.event;
}