(root)/
glib-2.79.0/
glib/
grefcount.c
       1  /* grefcount.c: Reference counting
       2   *
       3   * Copyright 2018  Emmanuele Bassi
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   *
       7   * This library is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 2.1 of the License, or (at your option) any later version.
      11   *
      12   * This library is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15   * Lesser General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU Lesser General Public
      18   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19   */
      20  
      21  #include "config.h"
      22  
      23  #include "grefcount.h"
      24  
      25  #include "gatomic.h"
      26  #include "gmessages.h"
      27  
      28  /**
      29   * grefcount:
      30   *
      31   * A type for implementing non-atomic reference count semantics.
      32   *
      33   * Use g_ref_count_init() to initialize it; g_ref_count_inc() to
      34   * increase the counter, and g_ref_count_dec() to decrease it.
      35   *
      36   * It is safe to use #grefcount only if you're expecting to operate
      37   * on the reference counter from a single thread. It is entirely up
      38   * to you to ensure that all reference count changes happen in the
      39   * same thread.
      40   *
      41   * See also: #gatomicrefcount
      42   *
      43   * Since: 2.58
      44   */
      45  
      46  /**
      47   * gatomicrefcount:
      48   *
      49   * A type for implementing atomic reference count semantics.
      50   *
      51   * Use g_atomic_ref_count_init() to initialize it; g_atomic_ref_count_inc()
      52   * to increase the counter, and g_atomic_ref_count_dec() to decrease it.
      53   *
      54   * It is safe to use #gatomicrefcount if you're expecting to operate on the
      55   * reference counter from multiple threads.
      56   *
      57   * See also: #grefcount
      58   *
      59   * Since: 2.58
      60   */
      61  
      62  /**
      63   * g_ref_count_init:
      64   * @rc: the address of a reference count variable
      65   *
      66   * Initializes a reference count variable to 1.
      67   *
      68   * Since: 2.58
      69   */
      70  void
      71  (g_ref_count_init) (grefcount *rc)
      72  {
      73    g_return_if_fail (rc != NULL);
      74  
      75    /* Non-atomic refcounting is implemented using the negative range
      76     * of signed integers:
      77     *
      78     * G_MININT                 Z¯< 0 > Z⁺                G_MAXINT
      79     * |----------------------------|----------------------------|
      80     *
      81     * Acquiring a reference moves us towards MININT, and releasing a
      82     * reference moves us towards 0.
      83     */
      84    *rc = -1;
      85  }
      86  
      87  /**
      88   * g_ref_count_inc:
      89   * @rc: the address of a reference count variable
      90   *
      91   * Increases the reference count.
      92   *
      93   * Since: 2.58
      94   */
      95  void
      96  (g_ref_count_inc) (grefcount *rc)
      97  {
      98    grefcount rrc;
      99  
     100    g_return_if_fail (rc != NULL);
     101  
     102    rrc = *rc;
     103  
     104    g_return_if_fail (rrc < 0);
     105  
     106    /* Check for saturation */
     107    if (rrc == G_MININT)
     108      {
     109        g_critical ("Reference count %p has reached saturation", rc);
     110        return;
     111      }
     112  
     113    rrc -= 1;
     114  
     115    *rc = rrc;
     116  }
     117  
     118  /**
     119   * g_ref_count_dec:
     120   * @rc: the address of a reference count variable
     121   *
     122   * Decreases the reference count.
     123   *
     124   * If %TRUE is returned, the reference count reached 0. After this point, @rc
     125   * is an undefined state and must be reinitialized with
     126   * g_ref_count_init() to be used again.
     127   *
     128   * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
     129   *
     130   * Since: 2.58
     131   */
     132  gboolean
     133  (g_ref_count_dec) (grefcount *rc)
     134  {
     135    grefcount rrc;
     136  
     137    g_return_val_if_fail (rc != NULL, FALSE);
     138  
     139    rrc = *rc;
     140  
     141    g_return_val_if_fail (rrc < 0, FALSE);
     142  
     143    rrc += 1;
     144    if (rrc == 0)
     145      return TRUE;
     146  
     147    *rc = rrc;
     148  
     149    return FALSE;
     150  }
     151  
     152  /**
     153   * g_ref_count_compare:
     154   * @rc: the address of a reference count variable
     155   * @val: the value to compare
     156   *
     157   * Compares the current value of @rc with @val.
     158   *
     159   * Returns: %TRUE if the reference count is the same
     160   *   as the given value
     161   *
     162   * Since: 2.58
     163   */
     164  gboolean
     165  (g_ref_count_compare) (grefcount *rc,
     166                         gint       val)
     167  {
     168    grefcount rrc;
     169  
     170    g_return_val_if_fail (rc != NULL, FALSE);
     171    g_return_val_if_fail (val >= 0, FALSE);
     172  
     173    rrc = *rc;
     174  
     175    if (val == G_MAXINT)
     176      return rrc == G_MININT;
     177  
     178    return rrc == -val;
     179  }
     180  
     181  /**
     182   * g_atomic_ref_count_init:
     183   * @arc: the address of an atomic reference count variable
     184   *
     185   * Initializes a reference count variable to 1.
     186   *
     187   * Since: 2.58
     188   */
     189  void
     190  (g_atomic_ref_count_init) (gatomicrefcount *arc)
     191  {
     192    g_return_if_fail (arc != NULL);
     193  
     194    /* Atomic refcounting is implemented using the positive range
     195     * of signed integers:
     196     *
     197     * G_MININT                 Z¯< 0 > Z⁺                G_MAXINT
     198     * |----------------------------|----------------------------|
     199     *
     200     * Acquiring a reference moves us towards MAXINT, and releasing a
     201     * reference moves us towards 0.
     202     */
     203    *arc = 1;
     204  }
     205  
     206  /**
     207   * g_atomic_ref_count_inc:
     208   * @arc: the address of an atomic reference count variable
     209   *
     210   * Atomically increases the reference count.
     211   *
     212   * Since: 2.58
     213   */
     214  void
     215  (g_atomic_ref_count_inc) (gatomicrefcount *arc)
     216  {
     217    gint old_value;
     218  
     219    g_return_if_fail (arc != NULL);
     220    old_value = g_atomic_int_add (arc, 1);
     221    g_return_if_fail (old_value > 0);
     222  
     223    if (old_value == G_MAXINT)
     224      g_critical ("Reference count has reached saturation");
     225  }
     226  
     227  /**
     228   * g_atomic_ref_count_dec:
     229   * @arc: the address of an atomic reference count variable
     230   *
     231   * Atomically decreases the reference count.
     232   *
     233   * If %TRUE is returned, the reference count reached 0. After this point, @arc
     234   * is an undefined state and must be reinitialized with
     235   * g_atomic_ref_count_init() to be used again.
     236   *
     237   * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
     238   *
     239   * Since: 2.58
     240   */
     241  gboolean
     242  (g_atomic_ref_count_dec) (gatomicrefcount *arc)
     243  {
     244    gint old_value;
     245  
     246    g_return_val_if_fail (arc != NULL, FALSE);
     247    old_value = g_atomic_int_add (arc, -1);
     248    g_return_val_if_fail (old_value > 0, FALSE);
     249  
     250    return old_value == 1;
     251  }
     252  
     253  /**
     254   * g_atomic_ref_count_compare:
     255   * @arc: the address of an atomic reference count variable
     256   * @val: the value to compare
     257   *
     258   * Atomically compares the current value of @arc with @val.
     259   *
     260   * Returns: %TRUE if the reference count is the same
     261   *   as the given value
     262   *
     263   * Since: 2.58
     264   */
     265  gboolean
     266  (g_atomic_ref_count_compare) (gatomicrefcount *arc,
     267                                gint             val)
     268  {
     269    g_return_val_if_fail (arc != NULL, FALSE);
     270    g_return_val_if_fail (val >= 0, FALSE);
     271  
     272    return g_atomic_int_get (arc) == val;
     273  }