(root)/
glib-2.79.0/
glib/
tests/
atomic.c
       1  /*
       2   * Copyright 2011 Red Hat, Inc.
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This program is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * See the included COPYING file for more information.
      12   */
      13  
      14  #include <glib.h>
      15  
      16  /* We want the g_atomic_pointer_get() macros to work when compiling third party
      17   * projects with -Wbad-function-cast.
      18   * See https://gitlab.gnome.org/GNOME/glib/issues/1041. */
      19  #pragma GCC diagnostic error "-Wbad-function-cast"
      20  
      21  static void
      22  test_types (void)
      23  {
      24    const gint *csp;
      25    const gint * const *cspp;
      26    guint u, u2;
      27    gint s, s2;
      28    gpointer vp, vp2, cp;
      29    const char *vp_str, *vp_str2;
      30    const char *volatile vp_str_vol;
      31    const char *str = "Hello";
      32    const char *old_str;
      33    int *ip, *ip2;
      34    guintptr gu, gu2;
      35    gboolean res;
      36  
      37    csp = &s;
      38    cspp = &csp;
      39  
      40    g_atomic_int_set (&u, 5);
      41    u2 = (guint) g_atomic_int_get (&u);
      42    g_assert_cmpint (u2, ==, 5);
      43    res = g_atomic_int_compare_and_exchange (&u, 6, 7);
      44    g_assert_false (res);
      45    g_assert_cmpint (u, ==, 5);
      46    res = g_atomic_int_compare_and_exchange_full (&u, 6, 7, &u2);
      47    g_assert_false (res);
      48    g_assert_cmpint (u, ==, 5);
      49    g_assert_cmpint (u2, ==, 5);
      50    g_atomic_int_add (&u, 1);
      51    g_assert_cmpint (u, ==, 6);
      52    g_atomic_int_inc (&u);
      53    g_assert_cmpint (u, ==, 7);
      54    res = g_atomic_int_dec_and_test (&u);
      55    g_assert_false (res);
      56    g_assert_cmpint (u, ==, 6);
      57    u2 = g_atomic_int_and (&u, 5);
      58    g_assert_cmpint (u2, ==, 6);
      59    g_assert_cmpint (u, ==, 4);
      60    u2 = g_atomic_int_or (&u, 8);
      61    g_assert_cmpint (u2, ==, 4);
      62    g_assert_cmpint (u, ==, 12);
      63    u2 = g_atomic_int_xor (&u, 4);
      64    g_assert_cmpint (u2, ==, 12);
      65    g_assert_cmpint (u, ==, 8);
      66    u2 = g_atomic_int_exchange (&u, 55);
      67    g_assert_cmpint (u2, ==, 8);
      68    g_assert_cmpint (u, ==, 55);
      69  
      70    g_atomic_int_set (&s, 5);
      71    s2 = g_atomic_int_get (&s);
      72    g_assert_cmpint (s2, ==, 5);
      73    res = g_atomic_int_compare_and_exchange (&s, 6, 7);
      74    g_assert_false (res);
      75    g_assert_cmpint (s, ==, 5);
      76    s2 = 0;
      77    res = g_atomic_int_compare_and_exchange_full (&s, 6, 7, &s2);
      78    g_assert_false (res);
      79    g_assert_cmpint (s, ==, 5);
      80    g_assert_cmpint (s2, ==, 5);
      81    g_atomic_int_add (&s, 1);
      82    g_assert_cmpint (s, ==, 6);
      83    g_atomic_int_inc (&s);
      84    g_assert_cmpint (s, ==, 7);
      85    res = g_atomic_int_dec_and_test (&s);
      86    g_assert_false (res);
      87    g_assert_cmpint (s, ==, 6);
      88    s2 = (gint) g_atomic_int_and (&s, 5);
      89    g_assert_cmpint (s2, ==, 6);
      90    g_assert_cmpint (s, ==, 4);
      91    s2 = (gint) g_atomic_int_or (&s, 8);
      92    g_assert_cmpint (s2, ==, 4);
      93    g_assert_cmpint (s, ==, 12);
      94    s2 = (gint) g_atomic_int_xor (&s, 4);
      95    g_assert_cmpint (s2, ==, 12);
      96    g_assert_cmpint (s, ==, 8);
      97    s2 = g_atomic_int_exchange (&s, 55);
      98    g_assert_cmpint (s2, ==, 8);
      99    g_assert_cmpint (s, ==, 55);
     100  
     101    g_atomic_pointer_set (&vp, 0);
     102    vp2 = g_atomic_pointer_get (&vp);
     103    g_assert_true (vp2 == 0);
     104    res = g_atomic_pointer_compare_and_exchange (&vp, &s, &s);
     105    g_assert_false (res);
     106    cp = &s;
     107    res = g_atomic_pointer_compare_and_exchange_full (&vp, &s, &s, &cp);
     108    g_assert_false (res);
     109    g_assert_null (cp);
     110    g_assert_true (vp == 0);
     111    res = g_atomic_pointer_compare_and_exchange (&vp, NULL, NULL);
     112    g_assert_true (res);
     113    g_assert_true (vp == 0);
     114    g_assert_null (g_atomic_pointer_exchange (&vp, &s));
     115    g_assert_true (vp == &s);
     116    res = g_atomic_pointer_compare_and_exchange_full (&vp, &s, NULL, &cp);
     117    g_assert_true (res);
     118    g_assert_true (cp == &s);
     119  
     120    g_atomic_pointer_set (&vp_str, NULL);
     121    res = g_atomic_pointer_compare_and_exchange (&vp_str, NULL, str);
     122    g_assert_true (res);
     123    g_assert_cmpstr (g_atomic_pointer_exchange (&vp_str, NULL), ==, str);
     124    g_assert_null (vp_str);
     125    res = g_atomic_pointer_compare_and_exchange_full (&vp_str, NULL, str, &vp_str2);
     126    g_assert_true (res);
     127    g_assert_cmpstr (vp_str, ==, str);
     128    g_assert_null (vp_str2);
     129    res = g_atomic_pointer_compare_and_exchange_full (&vp_str, (char *) str, NULL, &vp_str2);
     130    g_assert_true (res);
     131    g_assert_null (vp_str);
     132    g_assert_true (vp_str2 == str);
     133  
     134    /* Note that atomic variables should almost certainly not be marked as
     135     * `volatile` — see http://isvolatileusefulwiththreads.in/c/. This test exists
     136     * to make sure that we don’t warn when built against older third party code. */
     137  #pragma GCC diagnostic push
     138  #pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
     139    g_atomic_pointer_set (&vp_str_vol, NULL);
     140    g_atomic_pointer_set (&vp_str, str);
     141    res = g_atomic_pointer_compare_and_exchange (&vp_str_vol, NULL, str);
     142    g_assert_true (res);
     143    g_assert_cmpstr (g_atomic_pointer_exchange (&vp_str, NULL), ==, str);
     144    g_assert_null (vp_str);
     145  
     146    res = g_atomic_pointer_compare_and_exchange_full (&vp_str_vol, str, NULL, &old_str);
     147    g_assert_true (res);
     148    g_assert_true (old_str == str);
     149  #pragma GCC diagnostic pop
     150  
     151    g_atomic_pointer_set (&ip, 0);
     152    ip2 = g_atomic_pointer_get (&ip);
     153    g_assert_true (ip2 == 0);
     154    res = g_atomic_pointer_compare_and_exchange (&ip, NULL, NULL);
     155    g_assert_true (res);
     156    g_assert_true (ip == 0);
     157  
     158    res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, &s, &ip2);
     159    g_assert_true (res);
     160    g_assert_true (ip == &s);
     161    g_assert_cmpuint ((guintptr) ip2, ==, 0);
     162  
     163    res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, NULL, &ip2);
     164    g_assert_false (res);
     165    g_assert_true (ip == &s);
     166    g_assert_true (ip2 == &s);
     167  
     168    g_atomic_pointer_set (&gu, 0);
     169    vp2 = (gpointer) g_atomic_pointer_get (&gu);
     170    gu2 = (guintptr) vp2;
     171    g_assert_cmpuint (gu2, ==, 0);
     172    res = g_atomic_pointer_compare_and_exchange (&gu, NULL, (guintptr) NULL);
     173    g_assert_true (res);
     174    g_assert_cmpuint (gu, ==, 0);
     175    res = g_atomic_pointer_compare_and_exchange_full (&gu, (guintptr) NULL, (guintptr) NULL, &gu2);
     176    g_assert_true (res);
     177    g_assert_cmpuint (gu, ==, 0);
     178    g_assert_cmpuint (gu2, ==, 0);
     179    gu2 = (guintptr) g_atomic_pointer_add (&gu, 5);
     180    g_assert_cmpuint (gu2, ==, 0);
     181    g_assert_cmpuint (gu, ==, 5);
     182    gu2 = g_atomic_pointer_and (&gu, 6);
     183    g_assert_cmpuint (gu2, ==, 5);
     184    g_assert_cmpuint (gu, ==, 4);
     185    gu2 = g_atomic_pointer_or (&gu, 8);
     186    g_assert_cmpuint (gu2, ==, 4);
     187    g_assert_cmpuint (gu, ==, 12);
     188    gu2 = g_atomic_pointer_xor (&gu, 4);
     189    g_assert_cmpuint (gu2, ==, 12);
     190    g_assert_cmpuint (gu, ==, 8);
     191    vp_str2 = g_atomic_pointer_exchange (&vp_str, str);
     192    g_assert_cmpstr (vp_str, ==, str);
     193    g_assert_null (vp_str2);
     194  
     195    g_assert_cmpint (g_atomic_int_get (csp), ==, s);
     196    g_assert_true (g_atomic_pointer_get ((const gint **) cspp) == csp);
     197  
     198    /* repeat, without the macros */
     199  #undef g_atomic_int_set
     200  #undef g_atomic_int_get
     201  #undef g_atomic_int_compare_and_exchange
     202  #undef g_atomic_int_compare_and_exchange_full
     203  #undef g_atomic_int_exchange
     204  #undef g_atomic_int_add
     205  #undef g_atomic_int_inc
     206  #undef g_atomic_int_and
     207  #undef g_atomic_int_or
     208  #undef g_atomic_int_xor
     209  #undef g_atomic_int_dec_and_test
     210  #undef g_atomic_pointer_set
     211  #undef g_atomic_pointer_get
     212  #undef g_atomic_pointer_compare_and_exchange
     213  #undef g_atomic_pointer_compare_and_exchange_full
     214  #undef g_atomic_pointer_exchange
     215  #undef g_atomic_pointer_add
     216  #undef g_atomic_pointer_and
     217  #undef g_atomic_pointer_or
     218  #undef g_atomic_pointer_xor
     219  
     220    g_atomic_int_set ((gint*)&u, 5);
     221    u2 = (guint) g_atomic_int_get ((gint*)&u);
     222    g_assert_cmpint (u2, ==, 5);
     223    res = g_atomic_int_compare_and_exchange ((gint*)&u, 6, 7);
     224    g_assert_false (res);
     225    g_assert_cmpint (u, ==, 5);
     226    u2 = 0;
     227    res = g_atomic_int_compare_and_exchange_full ((gint*)&u, 6, 7, (gint*) &u2);
     228    g_assert_false (res);
     229    g_assert_cmpuint (u, ==, 5);
     230    g_assert_cmpuint (u2, ==, 5);
     231    g_atomic_int_add ((gint*)&u, 1);
     232    g_assert_cmpint (u, ==, 6);
     233    g_atomic_int_inc ((gint*)&u);
     234    g_assert_cmpint (u, ==, 7);
     235    res = g_atomic_int_dec_and_test ((gint*)&u);
     236    g_assert_false (res);
     237    g_assert_cmpint (u, ==, 6);
     238    u2 = g_atomic_int_and (&u, 5);
     239    g_assert_cmpint (u2, ==, 6);
     240    g_assert_cmpint (u, ==, 4);
     241    u2 = g_atomic_int_or (&u, 8);
     242    g_assert_cmpint (u2, ==, 4);
     243    g_assert_cmpint (u, ==, 12);
     244    u2 = g_atomic_int_xor (&u, 4);
     245    g_assert_cmpint (u2, ==, 12);
     246    u2 = g_atomic_int_exchange ((gint*) &u, 55);
     247    g_assert_cmpint (u2, ==, 8);
     248    g_assert_cmpint (u, ==, 55);
     249  
     250    g_atomic_int_set (&s, 5);
     251    s2 = g_atomic_int_get (&s);
     252    g_assert_cmpint (s2, ==, 5);
     253    res = g_atomic_int_compare_and_exchange (&s, 6, 7);
     254    g_assert_false (res);
     255    g_assert_cmpint (s, ==, 5);
     256    s2 = 0;
     257    res = g_atomic_int_compare_and_exchange_full (&s, 6, 7, &s2);
     258    g_assert_false (res);
     259    g_assert_cmpint (s, ==, 5);
     260    g_assert_cmpint (s2, ==, 5);
     261    g_atomic_int_add (&s, 1);
     262    g_assert_cmpint (s, ==, 6);
     263    g_atomic_int_inc (&s);
     264    g_assert_cmpint (s, ==, 7);
     265    res = g_atomic_int_dec_and_test (&s);
     266    g_assert_false (res);
     267    g_assert_cmpint (s, ==, 6);
     268    s2 = (gint) g_atomic_int_and ((guint*)&s, 5);
     269    g_assert_cmpint (s2, ==, 6);
     270    g_assert_cmpint (s, ==, 4);
     271    s2 = (gint) g_atomic_int_or ((guint*)&s, 8);
     272    g_assert_cmpint (s2, ==, 4);
     273    g_assert_cmpint (s, ==, 12);
     274    s2 = (gint) g_atomic_int_xor ((guint*)&s, 4);
     275    g_assert_cmpint (s2, ==, 12);
     276    g_assert_cmpint (s, ==, 8);
     277  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     278    s2 = g_atomic_int_exchange_and_add ((gint*)&s, 1);
     279  G_GNUC_END_IGNORE_DEPRECATIONS
     280    g_assert_cmpint (s2, ==, 8);
     281    g_assert_cmpint (s, ==, 9);
     282    s2 = g_atomic_int_exchange (&s, 55);
     283    g_assert_cmpint (s2, ==, 9);
     284    g_assert_cmpint (s, ==, 55);
     285  
     286    g_atomic_pointer_set (&vp, 0);
     287    vp2 = g_atomic_pointer_get (&vp);
     288    g_assert_true (vp2 == 0);
     289    res = g_atomic_pointer_compare_and_exchange (&vp, &s, &s);
     290    g_assert_false (res);
     291    g_assert_true (vp == 0);
     292    res = g_atomic_pointer_compare_and_exchange_full (&vp, &s, &s, &cp);
     293    g_assert_false (res);
     294    g_assert_null (vp);
     295    g_assert_null (cp);
     296    res = g_atomic_pointer_compare_and_exchange (&vp, NULL, NULL);
     297    g_assert_true (res);
     298    g_assert_true (vp == 0);
     299    res = g_atomic_pointer_compare_and_exchange_full (&vp, NULL, NULL, &cp);
     300    g_assert_true (res);
     301    g_assert_null (vp);
     302    g_assert_null (cp);
     303    g_assert_null (g_atomic_pointer_exchange (&vp, &s));
     304    g_assert_true (vp == &s);
     305  
     306    g_atomic_pointer_set (&vp_str, NULL);
     307    res = g_atomic_pointer_compare_and_exchange (&vp_str, NULL, (char *) str);
     308    g_assert_true (res);
     309    g_assert_cmpstr (g_atomic_pointer_exchange (&vp_str, NULL), ==, str);
     310    g_assert_null (vp_str);
     311    res = g_atomic_pointer_compare_and_exchange_full (&vp_str, NULL, (char *) str, &cp);
     312    g_assert_true (res);
     313    g_assert_cmpstr (vp_str, ==, str);
     314    g_assert_null (cp);
     315    res = g_atomic_pointer_compare_and_exchange_full (&vp_str, (char *) str, NULL, &cp);
     316    g_assert_true (res);
     317    g_assert_null (vp_str);
     318    g_assert_true (cp == str);
     319  
     320    /* Note that atomic variables should almost certainly not be marked as
     321     * `volatile` — see http://isvolatileusefulwiththreads.in/c/. This test exists
     322     * to make sure that we don’t warn when built against older third party code. */
     323    g_atomic_pointer_set (&vp_str_vol, NULL);
     324    g_atomic_pointer_set (&vp_str, (char *) str);
     325    res = g_atomic_pointer_compare_and_exchange (&vp_str_vol, NULL, (char *) str);
     326    g_assert_true (res);
     327    g_assert_cmpstr (g_atomic_pointer_exchange (&vp_str, NULL), ==, str);
     328    g_assert_null (vp_str);
     329  
     330    res = g_atomic_pointer_compare_and_exchange_full ((char **) &vp_str_vol, (char *) str, NULL, &old_str);
     331    g_assert_true (res);
     332    g_assert_true (old_str == str);
     333  
     334    g_atomic_pointer_set (&ip, 0);
     335    ip2 = g_atomic_pointer_get (&ip);
     336    g_assert_true (ip2 == 0);
     337    res = g_atomic_pointer_compare_and_exchange (&ip, NULL, NULL);
     338    g_assert_true (res);
     339    g_assert_true (ip == 0);
     340  
     341    res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, (gpointer) 1, &cp);
     342    g_assert_true (res);
     343    g_assert_cmpint ((guintptr) ip, ==, 1);
     344    g_assert_cmpuint ((guintptr) cp, ==, 0);
     345  
     346    res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, NULL, &cp);
     347    g_assert_false (res);
     348    g_assert_cmpuint ((guintptr) ip, ==, 1);
     349    g_assert_cmpuint ((guintptr) cp, ==, 1);
     350  
     351    g_atomic_pointer_set (&gu, 0);
     352    vp = g_atomic_pointer_get (&gu);
     353    gu2 = (guintptr) vp;
     354    g_assert_cmpuint (gu2, ==, 0);
     355    res = g_atomic_pointer_compare_and_exchange (&gu, NULL, NULL);
     356    g_assert_true (res);
     357    g_assert_cmpuint (gu, ==, 0);
     358    res = g_atomic_pointer_compare_and_exchange_full (&gu, NULL, NULL, &cp);
     359    g_assert_true (res);
     360    g_assert_cmpuint (gu, ==, 0);
     361    g_assert_cmpuint ((guintptr) cp, ==, 0);
     362    gu2 = (guintptr) g_atomic_pointer_add (&gu, 5);
     363    g_assert_cmpuint (gu2, ==, 0);
     364    g_assert_cmpuint (gu, ==, 5);
     365    gu2 = g_atomic_pointer_and (&gu, 6);
     366    g_assert_cmpuint (gu2, ==, 5);
     367    g_assert_cmpuint (gu, ==, 4);
     368    gu2 = g_atomic_pointer_or (&gu, 8);
     369    g_assert_cmpuint (gu2, ==, 4);
     370    g_assert_cmpuint (gu, ==, 12);
     371    gu2 = g_atomic_pointer_xor (&gu, 4);
     372    g_assert_cmpuint (gu2, ==, 12);
     373    g_assert_cmpuint (gu, ==, 8);
     374    vp2 = g_atomic_pointer_exchange (&gu, NULL);
     375    gu2 = (guintptr) vp2;
     376    g_assert_cmpuint (gu2, ==, 8);
     377    g_assert_null ((gpointer) gu);
     378  
     379    g_assert_cmpint (g_atomic_int_get (csp), ==, s);
     380    g_assert_true (g_atomic_pointer_get (cspp) == csp);
     381  }
     382  
     383  #define THREADS 10
     384  #define ROUNDS 10000
     385  
     386  gint bucket[THREADS];  /* never contested by threads, not accessed atomically */
     387  gint atomic;  /* (atomic) */
     388  
     389  static gpointer
     390  thread_func (gpointer data)
     391  {
     392    gint idx = GPOINTER_TO_INT (data);
     393    gint i;
     394    gint d;
     395  
     396    for (i = 0; i < ROUNDS; i++)
     397      {
     398        d = g_random_int_range (-10, 100);
     399        bucket[idx] += d;
     400        g_atomic_int_add (&atomic, d);
     401        g_thread_yield ();
     402      }
     403  
     404    return NULL;
     405  }
     406  
     407  static void
     408  test_threaded (void)
     409  {
     410    gint sum;
     411    gint i;
     412    GThread *threads[THREADS];
     413  
     414    atomic = 0;
     415    for (i = 0; i < THREADS; i++)
     416      bucket[i] = 0;
     417  
     418    for (i = 0; i < THREADS; i++)
     419      threads[i] = g_thread_new ("atomic", thread_func, GINT_TO_POINTER (i));
     420  
     421    for (i = 0; i < THREADS; i++)
     422      g_thread_join (threads[i]);
     423  
     424    sum = 0;
     425    for (i = 0; i < THREADS; i++)
     426      sum += bucket[i];
     427  
     428    g_assert_cmpint (sum, ==, atomic);
     429  }
     430  
     431  int
     432  main (int argc, char **argv)
     433  {
     434    g_test_init (&argc, &argv, NULL);
     435  
     436    g_test_add_func ("/atomic/types", test_types);
     437    g_test_add_func ("/atomic/threaded", test_threaded);
     438  
     439    return g_test_run ();
     440  }