1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 #include <unistd.h>
25 #include <cstdlib>
26 #include <ctime>
27 #include <poll.h>
28 #include <pthread.h>
29 
30 #include "tscore/ink_atomic.h"
31 #include "tscore/ink_queue.h"
32 #include "tscore/ink_thread.h"
33 
34 #ifndef LONG_ATOMICLIST_TEST
35 
36 #define MAX_ALIST_TEST 10
37 #define MAX_ALIST_ARRAY 100000
38 InkAtomicList al[MAX_ALIST_TEST];
39 void *al_test[MAX_ALIST_TEST][MAX_ALIST_ARRAY];
40 int al_done = 0;
41 
42 void *
testalist(void * ame)43 testalist(void *ame)
44 {
45   int me = static_cast<int>((uintptr_t)ame);
46   int j, k;
47   for (k = 0; k < MAX_ALIST_ARRAY; k++) {
48     ink_atomiclist_push(&al[k % MAX_ALIST_TEST], &al_test[me][k]);
49   }
50   void *x;
51   for (j = 0; j < 1000000; j++) {
52     if ((x = ink_atomiclist_pop(&al[me]))) {
53       ink_atomiclist_push(&al[rand() % MAX_ALIST_TEST], x);
54     }
55   }
56   ink_atomic_increment(&al_done, 1);
57   return nullptr;
58 }
59 #endif // !LONG_ATOMICLIST_TEST
60 
61 #ifdef LONG_ATOMICLIST_TEST
62 /************************************************************************/
63 #define MAX_ATOMIC_LISTS (4 * 1024)
64 #define MAX_ITEMS_PER_LIST (1 * 1024)
65 #define MAX_TEST_THREADS 64
66 static InkAtomicList alists[MAX_ATOMIC_LISTS];
67 struct listItem *items[MAX_ATOMIC_LISTS * MAX_ITEMS_PER_LIST];
68 
69 struct listItem {
70   int data1;
71   int data2;
72   void *link;
73   int data3;
74   int data4;
75   int check;
76 };
77 
78 void
init_data()79 init_data()
80 {
81   int j;
82   int ali;
83   struct listItem l;
84   struct listItem *plistItem;
85 
86   for (ali = 0; ali < MAX_ATOMIC_LISTS; ali++)
87     ink_atomiclist_init(&alists[ali], "alist", ((char *)&l.link - (char *)&l));
88 
89   for (ali = 0; ali < MAX_ATOMIC_LISTS; ali++) {
90     for (j = 0; j < MAX_ITEMS_PER_LIST; j++) {
91       plistItem        = (struct listItem *)malloc(sizeof(struct listItem));
92       items[ali + j]   = plistItem;
93       plistItem->data1 = ali + j;
94       plistItem->data2 = ali + rand();
95       plistItem->link  = 0;
96       plistItem->data3 = j + rand();
97       plistItem->data4 = ali + j + rand();
98       plistItem->check = (plistItem->data1 ^ plistItem->data2 ^ plistItem->data3 ^ plistItem->data4);
99       ink_atomiclist_push(&alists[ali], plistItem);
100     }
101   }
102 }
103 
104 void
cycle_data(void * d)105 cycle_data(void *d)
106 {
107   InkAtomicList *l;
108   struct listItem *pli;
109   struct listItem *pli_next;
110   int iterations;
111   int me;
112 
113   me         = (int)d;
114   iterations = 0;
115 
116   while (1) {
117     l = &alists[(me + rand()) % MAX_ATOMIC_LISTS];
118 
119     pli = (struct listItem *)ink_atomiclist_popall(l);
120     if (!pli)
121       continue;
122 
123     // Place listItems into random queues
124     while (pli) {
125       ink_assert((pli->data1 ^ pli->data2 ^ pli->data3 ^ pli->data4) == pli->check);
126       pli_next  = (struct listItem *)pli->link;
127       pli->link = 0;
128       ink_atomiclist_push(&alists[(me + rand()) % MAX_ATOMIC_LISTS], (void *)pli);
129       pli = pli_next;
130     }
131     iterations++;
132     poll(0, 0, 10); // 10 msec delay
133     if ((iterations % 100) == 0)
134       printf("%d ", me);
135   }
136 }
137 
138 /************************************************************************/
139 #endif // LONG_ATOMICLIST_TEST
140 
141 int
main(int,const char * [])142 main(int /* argc ATS_UNUSED */, const char * /* argv ATS_UNUSED */[])
143 {
144 #ifndef LONG_ATOMICLIST_TEST
145   int32_t m = 1, n = 100;
146   // int64 lm = 1LL, ln = 100LL;
147   const char *m2 = "hello";
148   char *n2;
149 
150   printf("sizeof(int32_t)==%d   sizeof(void *)==%d\n", static_cast<int>(sizeof(int32_t)), static_cast<int>(sizeof(void *)));
151 
152   printf("CAS: %d == 1  then  2\n", m);
153   n = ink_atomic_cas(&m, 1, 2);
154   printf("changed to: %d,  result=%s\n", m, n ? "true" : "false");
155 
156   printf("CAS: %d == 1  then  3\n", m);
157   n = ink_atomic_cas(&m, 1, 3);
158   printf("changed to: %d,  result=%s\n", m, n ? "true" : "false");
159 
160   printf("CAS pointer: '%s' == 'hello'  then  'new'\n", m2);
161   n = ink_atomic_cas(&m2, "hello", "new");
162   printf("changed to: %s, result=%s\n", m2, n ? (char *)"true" : (char *)"false");
163 
164   printf("CAS pointer: '%s' == 'hello'  then  'new2'\n", m2);
165   n = ink_atomic_cas(&m2, m2, "new2");
166   printf("changed to: %s, result=%s\n", m2, n ? "true" : "false");
167 
168   n = 100;
169   printf("Atomic Inc of %d\n", n);
170   m = ink_atomic_increment(static_cast<int *>(&n), 1);
171   printf("changed to: %d,  result=%d\n", n, m);
172 
173   printf("Atomic Fetch-and-Add 2 to pointer to '%s'\n", m2);
174   n2 = static_cast<char *>(ink_atomic_increment((void **)&m2, (void *)2));
175   printf("changed to: %s,  result=%s\n", m2, n2);
176 
177   printf("Testing atomic lists\n");
178   {
179     int ali;
180     srand(time(nullptr));
181     printf("sizeof(al_test) = %d\n", static_cast<int>(sizeof(al_test)));
182     memset(&al_test[0][0], 0, sizeof(al_test));
183     for (ali = 0; ali < MAX_ALIST_TEST; ali++) {
184       ink_atomiclist_init(&al[ali], "foo", 0);
185     }
186     for (ali = 0; ali < MAX_ALIST_TEST; ali++) {
187       ink_thread tid;
188       pthread_attr_t attr;
189 
190       pthread_attr_init(&attr);
191 #if !defined(freebsd)
192       pthread_attr_setstacksize(&attr, 1024 * 1024);
193 #endif
194       ink_assert(pthread_create(&tid, &attr, testalist, (void *)((intptr_t)ali)) == 0);
195     }
196     while (al_done != MAX_ALIST_TEST) {
197       sleep(1);
198     }
199   }
200 #endif // !LONG_ATOMICLIST_TEST
201 
202 #ifdef LONG_ATOMICLIST_TEST
203   printf("Testing atomic lists (long version)\n");
204   {
205     int id;
206 
207     init_data();
208     for (id = 0; id < MAX_TEST_THREADS; id++) {
209       ink_assert(thr_create(NULL, 0, cycle_data, (void *)id, THR_NEW_LWP, NULL) == 0);
210     }
211   }
212   while (1) {
213     poll(0, 0, 10); // 10 msec delay
214   }
215 #endif // LONG_ATOMICLIST_TEST
216 
217   return 0;
218 }
219