(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
di-sync-multithread.c
       1  /* { dg-do run } */
       2  /* { dg-require-effective-target sync_long_long_runtime } */
       3  /* { dg-require-effective-target pthread_h } */
       4  /* { dg-require-effective-target pthread } */
       5  /* { dg-options "-pthread -std=gnu99" } */
       6  /* { dg-additional-options "-march=pentium" { target { { i?86-*-* x86_64-*-* } && ia32 } } } */
       7  
       8  /* test of long long atomic ops performed in parallel in 3 pthreads
       9     david.gilbert@linaro.org */
      10  
      11  #include <pthread.h>
      12  #include <unistd.h>
      13  #ifdef _WIN32
      14  #include <windows.h>
      15  #endif
      16  
      17  /*#define DEBUGIT 1 */
      18  
      19  #ifdef DEBUGIT
      20  #include <stdio.h>
      21  
      22  #define DOABORT(x,...) {\
      23  	 fprintf (stderr, x, __VA_ARGS__); fflush (stderr); abort ();\
      24  	 }
      25  
      26  #else
      27  
      28  #define DOABORT(x,...) abort ();
      29  
      30  #endif
      31  
      32  /* Passed to each thread to describe which bits it is going to work on.  */
      33  struct threadwork {
      34    unsigned long long count; /* incremented each time the worker loops.  */
      35    unsigned int thread;    /* ID */
      36    unsigned int addlsb;    /* 8 bit */
      37    unsigned int logic1lsb; /* 5 bit */
      38    unsigned int logic2lsb; /* 8 bit */
      39  };
      40  
      41  /* The shared word where all the atomic work is done.  */
      42  static volatile long long workspace;
      43  
      44  /* A shared word to tell the workers to quit when non-0.  */
      45  static long long doquit;
      46  
      47  extern void abort (void);
      48  
      49  /* Note this test doesn't test the return values much.  */
      50  void*
      51  worker (void* data)
      52  {
      53    struct threadwork *tw = (struct threadwork*)data;
      54    long long add1bit = 1ll << tw->addlsb;
      55    long long logic1bit = 1ll << tw->logic1lsb;
      56    long long logic2bit = 1ll << tw->logic2lsb;
      57  
      58    /* Clear the bits we use.  */
      59    __sync_and_and_fetch (&workspace, ~(0xffll * add1bit));
      60    __sync_fetch_and_and (&workspace, ~(0x1fll * logic1bit));
      61    __sync_fetch_and_and (&workspace, ~(0xffll * logic2bit));
      62  
      63    do
      64      {
      65        long long tmp1, tmp2, tmp3;
      66        /* OK, lets try and do some stuff to the workspace - by the end
      67           of the main loop our area should be the same as it is now - i.e. 0.  */
      68  
      69        /* Push the arithmetic section up to 128 - one of the threads will
      70           case this to carry across the 32bit boundary.  */
      71        for (tmp2 = 0; tmp2 < 64; tmp2++)
      72  	{
      73  	  sched_yield ();
      74  
      75  	  /* Add 2 using the two different adds.  */
      76  	  tmp1 = __sync_add_and_fetch (&workspace, add1bit);
      77  	  tmp3 = __sync_fetch_and_add (&workspace, add1bit);
      78  
      79  	  /* The value should be the intermediate add value in both cases.  */
      80  	  if ((tmp1 & (add1bit * 0xff)) != (tmp3 & (add1bit * 0xff)))
      81  	    DOABORT ("Mismatch of add intermediates on thread %d "
      82  			"workspace=0x%llx tmp1=0x%llx "
      83  			"tmp2=0x%llx tmp3=0x%llx\n",
      84  			 tw->thread, workspace, tmp1, tmp2, tmp3);
      85  	}
      86  
      87        /* Set the logic bits.  */
      88        tmp2=__sync_or_and_fetch (&workspace,
      89  			  0x1fll * logic1bit | 0xffll * logic2bit);
      90  
      91        /* Check the logic bits are set and the arithmetic value is correct.  */
      92        if ((tmp2 & (0x1fll * logic1bit | 0xffll * logic2bit
      93  			| 0xffll * add1bit))
      94  	  != (0x1fll * logic1bit | 0xffll * logic2bit | 0x80ll * add1bit))
      95  	DOABORT ("Midloop check failed on thread %d "
      96  			"workspace=0x%llx tmp2=0x%llx "
      97  			"masktmp2=0x%llx expected=0x%llx\n",
      98  		tw->thread, workspace, tmp2,
      99  		tmp2 & (0x1fll * logic1bit | 0xffll * logic2bit |
     100  			 0xffll * add1bit),
     101  		(0x1fll * logic1bit | 0xffll * logic2bit | 0x80ll * add1bit));
     102  
     103        /* Pull the arithmetic set back down to 0 - again this should cause a
     104  	 carry across the 32bit boundary in one thread.  */
     105  
     106        for (tmp2 = 0; tmp2 < 64; tmp2++)
     107  	{
     108  	  sched_yield ();
     109  
     110  	  /* Subtract 2 using the two different subs.  */
     111  	  tmp1=__sync_sub_and_fetch (&workspace, add1bit);
     112  	  tmp3=__sync_fetch_and_sub (&workspace, add1bit);
     113  
     114  	  /* The value should be the intermediate sub value in both cases.  */
     115  	  if ((tmp1 & (add1bit * 0xff)) != (tmp3 & (add1bit * 0xff)))
     116  	    DOABORT ("Mismatch of sub intermediates on thread %d "
     117  			"workspace=0x%llx tmp1=0x%llx "
     118  			"tmp2=0x%llx tmp3=0x%llx\n",
     119  			tw->thread, workspace, tmp1, tmp2, tmp3);
     120  	}
     121  
     122  
     123        /* Clear the logic bits.  */
     124        __sync_fetch_and_xor (&workspace, 0x1fll * logic1bit);
     125        tmp3=__sync_and_and_fetch (&workspace, ~(0xffll * logic2bit));
     126  
     127        /* The logic bits and the arithmetic bits should be zero again.  */
     128        if (tmp3 & (0x1fll * logic1bit | 0xffll * logic2bit | 0xffll * add1bit))
     129  	DOABORT ("End of worker loop; bits none 0 on thread %d "
     130  			"workspace=0x%llx tmp3=0x%llx "
     131  			"mask=0x%llx maskedtmp3=0x%llx\n",
     132  		tw->thread, workspace, tmp3, (0x1fll * logic1bit |
     133  			0xffll * logic2bit | 0xffll * add1bit),
     134  		tmp3 & (0x1fll * logic1bit | 0xffll * logic2bit | 0xffll * add1bit));
     135  
     136        __sync_add_and_fetch (&tw->count, 1);
     137      }
     138    while (!__sync_bool_compare_and_swap (&doquit, 1, 1));
     139  
     140    pthread_exit (0);
     141  }
     142  
     143  int
     144  main ()
     145  {
     146    /* We have 3 threads doing three sets of operations, an 8 bit
     147       arithmetic field, a 5 bit logic field and an 8 bit logic
     148       field (just to pack them all in).
     149  
     150    6      5       4       4       3       2       1
     151    3      6       8       0       2       4       6       8       0
     152    |...,...|...,...|...,...|...,...|...,...|...,...|...,...|...,...
     153    - T0   --  T1  -- T2   --T2 --  T0  -*- T2-- T1-- T1   -***- T0-
     154     logic2  logic2  arith   log2  arith  log1 log1  arith     log1
     155  
     156    */
     157    unsigned int t;
     158    long long tmp;
     159    int err;
     160  
     161    struct threadwork tw[3]={
     162      { 0ll, 0, 27, 0, 56 },
     163      { 0ll, 1,  8,16, 48 },
     164      { 0ll, 2, 40,21, 35 }
     165    };
     166  
     167    pthread_t threads[3];
     168  
     169    __sync_lock_release (&doquit);
     170  
     171    /* Get the work space into a known value - All 1's.  */
     172    __sync_lock_release (&workspace); /* Now all 0.  */
     173    tmp = __sync_val_compare_and_swap (&workspace, 0, -1ll);
     174    if (tmp!=0)
     175      DOABORT ("Initial __sync_val_compare_and_swap wasn't 0 workspace=0x%llx "
     176  		"tmp=0x%llx\n", workspace,tmp);
     177  
     178    for (t = 0; t < 3; t++)
     179    {
     180      err=pthread_create (&threads[t], NULL , worker, &tw[t]);
     181      if (err) DOABORT ("pthread_create failed on thread %d with error %d\n",
     182  	t, err);
     183    };
     184  
     185    sched_yield ();
     186  
     187  #ifdef _WIN32
     188    Sleep (5000);
     189  #else
     190    sleep (5);
     191  #endif
     192  
     193    /* Stop please.  */
     194    __sync_lock_test_and_set (&doquit, 1ll);
     195  
     196    sched_yield ();
     197  
     198    for (t = 0; t < 3; t++)
     199      {
     200        err=pthread_join (threads[t], NULL);
     201        if (err)
     202  	DOABORT ("pthread_join failed on thread %d with error %d\n", t, err);
     203      };
     204  
     205    __sync_synchronize ();
     206  
     207    /* OK, so all the workers have finished -
     208       the workers should have zero'd their workspace, the unused areas
     209       should still be 1.  */
     210    if (!__sync_bool_compare_and_swap (&workspace, 0x040000e0ll, 0))
     211      DOABORT ("End of run workspace mismatch, got %llx\n", workspace);
     212  
     213    /* All the workers should have done some work.  */
     214    for (t = 0; t < 3; t++)
     215      {
     216        if (tw[t].count == 0) DOABORT ("Worker %d gave 0 count\n", t);
     217      };
     218  
     219    return 0;
     220  }
     221