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
 | 
			
		||||
      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
 | 
			
		||||
        q = @object.call
 | 
			
		||||
        -> { q.send(@method, timeout: "1") }.should raise_error(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,7 +73,13 @@ describe :sizedqueue_enq, shared: true do
 | 
			
		|||
        t.join
 | 
			
		||||
      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 << 1
 | 
			
		||||
        t = Thread.new {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1029,13 +1029,19 @@ static VALUE
 | 
			
		|||
queue_do_pop(VALUE self, struct rb_queue *q, int should_block, VALUE timeout)
 | 
			
		||||
{
 | 
			
		||||
    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) {
 | 
			
		||||
        if (!should_block) {
 | 
			
		||||
            rb_raise(rb_eThreadError, "queue empty");
 | 
			
		||||
        }
 | 
			
		||||
        else if (queue_closed_p(self)) {
 | 
			
		||||
        if (queue_closed_p(self)) {
 | 
			
		||||
            return queue_closed_result(self, q);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1232,16 +1238,22 @@ rb_szqueue_max_set(VALUE self, VALUE vmax)
 | 
			
		|||
static VALUE
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
        if (RTEST(non_block)) {
 | 
			
		||||
            rb_raise(rb_eThreadError, "queue full");
 | 
			
		||||
        }
 | 
			
		||||
        else if (queue_closed_p(self)) {
 | 
			
		||||
            break;
 | 
			
		||||
        if (queue_closed_p(self)) {
 | 
			
		||||
            raise_closed_queue_error(self);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            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);
 | 
			
		||||
            if (!NIL_P(timeout) && rb_hrtime_now() >= end) {
 | 
			
		||||
                timed_out = true;
 | 
			
		||||
                break;
 | 
			
		||||
                return Qnil;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (queue_closed_p(self)) {
 | 
			
		||||
        raise_closed_queue_error(self);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (timed_out) return Qnil;
 | 
			
		||||
 | 
			
		||||
    return queue_do_push(self, &sq->q, object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ class Thread
 | 
			
		|||
    # +ThreadError+ is raised.
 | 
			
		||||
    #
 | 
			
		||||
    # 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)
 | 
			
		||||
      if non_block && timeout
 | 
			
		||||
        raise ArgumentError, "can't set a timeout if non_block is enabled"
 | 
			
		||||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ class Thread
 | 
			
		|||
    # suspended, and +ThreadError+ is raised.
 | 
			
		||||
    #
 | 
			
		||||
    # 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)
 | 
			
		||||
      if non_block && timeout
 | 
			
		||||
        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.
 | 
			
		||||
    #
 | 
			
		||||
    # 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+.
 | 
			
		||||
    def push(object, non_block = false, timeout: nil)
 | 
			
		||||
      if non_block && timeout
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue