(root)/
glibc-2.38/
nptl/
sem_post.c
       1  /* sem_post -- post to a POSIX semaphore.  Generic futex-using version.
       2     Copyright (C) 2003-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 <atomic.h>
      20  #include <errno.h>
      21  #include <sysdep.h>
      22  #include <lowlevellock.h>	/* lll_futex* used by the old code.  */
      23  #include <futex-internal.h>
      24  #include <internaltypes.h>
      25  #include <semaphore.h>
      26  
      27  #include <shlib-compat.h>
      28  
      29  
      30  /* See sem_wait for an explanation of the algorithm.  */
      31  int
      32  __new_sem_post (sem_t *sem)
      33  {
      34    struct new_sem *isem = (struct new_sem *) sem;
      35    int private = isem->private;
      36  
      37  #if __HAVE_64B_ATOMICS
      38    /* Add a token to the semaphore.  We use release MO to make sure that a
      39       thread acquiring this token synchronizes with us and other threads that
      40       added tokens before (the release sequence includes atomic RMW operations
      41       by other threads).  */
      42    /* TODO Use atomic_fetch_add to make it scale better than a CAS loop?  */
      43    uint64_t d = atomic_load_relaxed (&isem->data);
      44    do
      45      {
      46        if ((d & SEM_VALUE_MASK) == SEM_VALUE_MAX)
      47  	{
      48  	  __set_errno (EOVERFLOW);
      49  	  return -1;
      50  	}
      51      }
      52    while (!atomic_compare_exchange_weak_release (&isem->data, &d, d + 1));
      53  
      54    /* If there is any potentially blocked waiter, wake one of them.  */
      55    if ((d >> SEM_NWAITERS_SHIFT) > 0)
      56      futex_wake (((unsigned int *) &isem->data) + SEM_VALUE_OFFSET, 1, private);
      57  #else
      58    /* Add a token to the semaphore.  Similar to 64b version.  */
      59    unsigned int v = atomic_load_relaxed (&isem->value);
      60    do
      61      {
      62        if ((v >> SEM_VALUE_SHIFT) == SEM_VALUE_MAX)
      63  	{
      64  	  __set_errno (EOVERFLOW);
      65  	  return -1;
      66  	}
      67      }
      68    while (!atomic_compare_exchange_weak_release
      69  	 (&isem->value, &v, v + (1 << SEM_VALUE_SHIFT)));
      70  
      71    /* If there is any potentially blocked waiter, wake one of them.  */
      72    if ((v & SEM_NWAITERS_MASK) != 0)
      73      futex_wake (&isem->value, 1, private);
      74  #endif
      75  
      76    return 0;
      77  }
      78  versioned_symbol (libpthread, __new_sem_post, sem_post, GLIBC_2_34);
      79  
      80  #if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_1, GLIBC_2_34)
      81  compat_symbol (libpthread, __new_sem_post, sem_post, GLIBC_2_1);
      82  #endif
      83  
      84  #if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
      85  int
      86  attribute_compat_text_section
      87  __old_sem_post (sem_t *sem)
      88  {
      89    unsigned int *futex = (unsigned int *) sem;
      90  
      91    /* We must need to synchronize with consumers of this token, so the atomic
      92       increment must have release MO semantics.  */
      93    atomic_write_barrier ();
      94    atomic_fetch_add_release (futex, 1);
      95    /* We always have to assume it is a shared semaphore.  */
      96    futex_wake (futex, 1, LLL_SHARED);
      97    return 0;
      98  }
      99  compat_symbol (libpthread, __old_sem_post, sem_post, GLIBC_2_0);
     100  #endif