mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
thread_sync.c: Clarify and document the behavior of timeout == 0
[Feature #18982] Instead of introducing an `exception: false` argument to have `non_block` return nil rather than raise, we can clearly document that a timeout of 0 immediately returns. The code is refactored a bit to avoid doing a time calculation in such case.
This commit is contained in:
parent
7db29de008
commit
60defe0a68
Notes:
git
2022-10-17 14:56:26 +00:00
4 changed files with 42 additions and 24 deletions
|
@ -87,6 +87,13 @@ describe :queue_deq, shared: true do
|
||||||
t.join
|
t.join
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "immediately returns nil if no item is available and the timeout is 0" do
|
||||||
|
q = @object.call
|
||||||
|
q << 1
|
||||||
|
q.send(@method, timeout: 0).should == 1
|
||||||
|
q.send(@method, timeout: 0).should == nil
|
||||||
|
end
|
||||||
|
|
||||||
it "raise TypeError if timeout is not a valid numeric" do
|
it "raise TypeError if timeout is not a valid numeric" do
|
||||||
q = @object.call
|
q = @object.call
|
||||||
-> { q.send(@method, timeout: "1") }.should raise_error(
|
-> { q.send(@method, timeout: "1") }.should raise_error(
|
||||||
|
|
|
@ -73,7 +73,13 @@ describe :sizedqueue_enq, shared: true do
|
||||||
t.join
|
t.join
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns nil if no item is available in time" do
|
it "returns nil if no space is avialable and timeout is 0" do
|
||||||
|
q = @object.call(1)
|
||||||
|
q.send(@method, 1, timeout: 0).should == q
|
||||||
|
q.send(@method, 2, timeout: 0).should == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nil if no space is available in time" do
|
||||||
q = @object.call(1)
|
q = @object.call(1)
|
||||||
q << 1
|
q << 1
|
||||||
t = Thread.new {
|
t = Thread.new {
|
||||||
|
|
|
@ -1029,13 +1029,19 @@ static VALUE
|
||||||
queue_do_pop(VALUE self, struct rb_queue *q, int should_block, VALUE timeout)
|
queue_do_pop(VALUE self, struct rb_queue *q, int should_block, VALUE timeout)
|
||||||
{
|
{
|
||||||
check_array(self, q->que);
|
check_array(self, q->que);
|
||||||
rb_hrtime_t end = queue_timeout2hrtime(timeout);
|
if (RARRAY_LEN(q->que) == 0) {
|
||||||
|
if (!should_block) {
|
||||||
|
rb_raise(rb_eThreadError, "queue empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RTEST(rb_equal(INT2FIX(0), timeout))) {
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_hrtime_t end = queue_timeout2hrtime(timeout);
|
||||||
while (RARRAY_LEN(q->que) == 0) {
|
while (RARRAY_LEN(q->que) == 0) {
|
||||||
if (!should_block) {
|
if (queue_closed_p(self)) {
|
||||||
rb_raise(rb_eThreadError, "queue empty");
|
|
||||||
}
|
|
||||||
else if (queue_closed_p(self)) {
|
|
||||||
return queue_closed_result(self, q);
|
return queue_closed_result(self, q);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1232,16 +1238,22 @@ rb_szqueue_max_set(VALUE self, VALUE vmax)
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_szqueue_push(rb_execution_context_t *ec, VALUE self, VALUE object, VALUE non_block, VALUE timeout)
|
rb_szqueue_push(rb_execution_context_t *ec, VALUE self, VALUE object, VALUE non_block, VALUE timeout)
|
||||||
{
|
{
|
||||||
rb_hrtime_t end = queue_timeout2hrtime(timeout);
|
|
||||||
bool timed_out = false;
|
|
||||||
struct rb_szqueue *sq = szqueue_ptr(self);
|
struct rb_szqueue *sq = szqueue_ptr(self);
|
||||||
|
|
||||||
|
if (queue_length(self, &sq->q) >= sq->max) {
|
||||||
|
if (RTEST(non_block)) {
|
||||||
|
rb_raise(rb_eThreadError, "queue full");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RTEST(rb_equal(INT2FIX(0), timeout))) {
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_hrtime_t end = queue_timeout2hrtime(timeout);
|
||||||
while (queue_length(self, &sq->q) >= sq->max) {
|
while (queue_length(self, &sq->q) >= sq->max) {
|
||||||
if (RTEST(non_block)) {
|
if (queue_closed_p(self)) {
|
||||||
rb_raise(rb_eThreadError, "queue full");
|
raise_closed_queue_error(self);
|
||||||
}
|
|
||||||
else if (queue_closed_p(self)) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rb_execution_context_t *ec = GET_EC();
|
rb_execution_context_t *ec = GET_EC();
|
||||||
|
@ -1262,18 +1274,11 @@ rb_szqueue_push(rb_execution_context_t *ec, VALUE self, VALUE object, VALUE non_
|
||||||
};
|
};
|
||||||
rb_ensure(queue_sleep, (VALUE)&queue_sleep_arg, szqueue_sleep_done, (VALUE)&queue_waiter);
|
rb_ensure(queue_sleep, (VALUE)&queue_sleep_arg, szqueue_sleep_done, (VALUE)&queue_waiter);
|
||||||
if (!NIL_P(timeout) && rb_hrtime_now() >= end) {
|
if (!NIL_P(timeout) && rb_hrtime_now() >= end) {
|
||||||
timed_out = true;
|
return Qnil;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queue_closed_p(self)) {
|
|
||||||
raise_closed_queue_error(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timed_out) return Qnil;
|
|
||||||
|
|
||||||
return queue_do_push(self, &sq->q, object);
|
return queue_do_push(self, &sq->q, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Thread
|
||||||
# +ThreadError+ is raised.
|
# +ThreadError+ is raised.
|
||||||
#
|
#
|
||||||
# If +timeout+ seconds have passed and no data is available +nil+ is
|
# If +timeout+ seconds have passed and no data is available +nil+ is
|
||||||
# returned.
|
# returned. If +timeout+ is +0+ it returns immediately.
|
||||||
def pop(non_block = false, timeout: nil)
|
def pop(non_block = false, timeout: nil)
|
||||||
if non_block && timeout
|
if non_block && timeout
|
||||||
raise ArgumentError, "can't set a timeout if non_block is enabled"
|
raise ArgumentError, "can't set a timeout if non_block is enabled"
|
||||||
|
@ -32,7 +32,7 @@ class Thread
|
||||||
# suspended, and +ThreadError+ is raised.
|
# suspended, and +ThreadError+ is raised.
|
||||||
#
|
#
|
||||||
# If +timeout+ seconds have passed and no data is available +nil+ is
|
# If +timeout+ seconds have passed and no data is available +nil+ is
|
||||||
# returned.
|
# returned. If +timeout+ is +0+ it returns immediately.
|
||||||
def pop(non_block = false, timeout: nil)
|
def pop(non_block = false, timeout: nil)
|
||||||
if non_block && timeout
|
if non_block && timeout
|
||||||
raise ArgumentError, "can't set a timeout if non_block is enabled"
|
raise ArgumentError, "can't set a timeout if non_block is enabled"
|
||||||
|
@ -54,7 +54,7 @@ class Thread
|
||||||
# thread isn't suspended, and +ThreadError+ is raised.
|
# thread isn't suspended, and +ThreadError+ is raised.
|
||||||
#
|
#
|
||||||
# If +timeout+ seconds have passed and no space is available +nil+ is
|
# If +timeout+ seconds have passed and no space is available +nil+ is
|
||||||
# returned.
|
# returned. If +timeout+ is +0+ it returns immediately.
|
||||||
# Otherwise it returns +self+.
|
# Otherwise it returns +self+.
|
||||||
def push(object, non_block = false, timeout: nil)
|
def push(object, non_block = false, timeout: nil)
|
||||||
if non_block && timeout
|
if non_block && timeout
|
||||||
|
|
Loading…
Reference in a new issue