(root)/
glibc-2.38/
sysdeps/
htl/
pt-rwlock-timedrdlock.c
       1  /* Acquire a rwlock for reading.  Generic version.
       2     Copyright (C) 2002-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library;  if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <pthread.h>
      20  #include <assert.h>
      21  #include <time.h>
      22  
      23  #include <pt-internal.h>
      24  
      25  /* Acquire the rwlock *RWLOCK for reading blocking until *ABSTIME if
      26     it is already held.  As a GNU extension, if TIMESPEC is NULL then
      27     wait forever.  */
      28  int
      29  __pthread_rwlock_timedrdlock_internal (struct __pthread_rwlock *rwlock,
      30  				       clockid_t clockid,
      31  				       const struct timespec *abstime)
      32  {
      33    error_t err;
      34    int drain;
      35    struct __pthread *self;
      36  
      37    __pthread_spin_wait (&rwlock->__lock);
      38    if (__pthread_spin_trylock (&rwlock->__held) == 0)
      39      /* Successfully acquired the lock.  */
      40      {
      41        assert (rwlock->__readerqueue == 0);
      42        assert (rwlock->__writerqueue == 0);
      43        assert (rwlock->__readers == 0);
      44  
      45        rwlock->__readers = 1;
      46        __pthread_spin_unlock (&rwlock->__lock);
      47        return 0;
      48      }
      49    else
      50      /* Lock is held, but is held by a reader?  */
      51    if (rwlock->__readers > 0)
      52      /* Just add ourself to number of readers.  */
      53      {
      54        assert (rwlock->__readerqueue == 0);
      55        rwlock->__readers++;
      56        __pthread_spin_unlock (&rwlock->__lock);
      57        return 0;
      58      }
      59  
      60    /* The lock is busy.  */
      61  
      62    /* Better be blocked by a writer.  */
      63    assert (rwlock->__readers == 0);
      64  
      65    if (abstime != NULL && ! valid_nanoseconds (abstime->tv_nsec))
      66      {
      67        __pthread_spin_unlock (&rwlock->__lock);
      68        return EINVAL;
      69      }
      70  
      71    self = _pthread_self ();
      72  
      73    /* Add ourself to the queue.  */
      74    __pthread_enqueue (&rwlock->__readerqueue, self);
      75    __pthread_spin_unlock (&rwlock->__lock);
      76  
      77    /* Block the thread.  */
      78    if (abstime != NULL)
      79      err = __pthread_timedblock (self, abstime, clockid);
      80    else
      81      {
      82        err = 0;
      83        __pthread_block (self);
      84      }
      85  
      86    __pthread_spin_wait (&rwlock->__lock);
      87    if (self->prevp == NULL)
      88      /* Another thread removed us from the queue, which means a wakeup message
      89         has been sent.  It was either consumed while we were blocking, or
      90         queued after we timed out and before we acquired the rwlock lock, in
      91         which case the message queue must be drained.  */
      92      drain = err ? 1 : 0;
      93    else
      94      {
      95        /* We're still in the queue.  No one attempted to wake us up, i.e. we
      96           timed out.  */
      97        __pthread_dequeue (self);
      98        drain = 0;
      99      }
     100    __pthread_spin_unlock (&rwlock->__lock);
     101  
     102    if (drain)
     103      __pthread_block (self);
     104  
     105    if (err)
     106      {
     107        assert (err == ETIMEDOUT);
     108        return err;
     109      }
     110  
     111    /* The reader count has already been increment by whoever woke us
     112       up.  */
     113  
     114    assert (rwlock->__readers > 0);
     115  
     116    return 0;
     117  }
     118  
     119  int
     120  __pthread_rwlock_timedrdlock (struct __pthread_rwlock *rwlock,
     121  			      const struct timespec *abstime)
     122  {
     123    return __pthread_rwlock_timedrdlock_internal (rwlock, CLOCK_REALTIME, abstime);
     124  }
     125  weak_alias (__pthread_rwlock_timedrdlock, pthread_rwlock_timedrdlock)
     126  
     127  int
     128  __pthread_rwlock_clockrdlock (struct __pthread_rwlock *rwlock,
     129  			      clockid_t clockid,
     130  			      const struct timespec *abstime)
     131  {
     132    return __pthread_rwlock_timedrdlock_internal (rwlock, clockid, abstime);
     133  }
     134  weak_alias (__pthread_rwlock_clockrdlock, pthread_rwlock_clockrdlock)