Do not precalculate OCB offset L0+L1+L0
[libgcrypt.git] / tests / t-lock.c
1 /* t-lock.c - Check the lock functions
2  * Copyright (C) 2014 g10 Code GmbH
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #if HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #if HAVE_PTHREAD
31 # include <pthread.h>
32 #endif
33
34 #define PGM "t-lock"
35
36 #include "t-common.h"
37 #include "../src/gcrypt-testapi.h"
38
39 /* Mingw requires us to include windows.h after winsock2.h which is
40    included by gcrypt.h.  */
41 #ifdef _WIN32
42 # include <windows.h>
43 #endif
44
45 #ifdef _WIN32
46 # define THREAD_RET_TYPE  DWORD WINAPI
47 # define THREAD_RET_VALUE 0
48 #else
49 # define THREAD_RET_TYPE  void *
50 # define THREAD_RET_VALUE NULL
51 #endif
52
53
54 /* Number of threads to run.  */
55 #define N_NONCE_THREADS 8
56 /* Number of interations.  */
57 #define N_NONCE_ITERATIONS 1000
58 /* Requested nonce size.  */
59 #define NONCE_SIZE  11
60
61
62 /* This tests works by having a a couple of accountant threads which do
63    random transactions between accounts and a revision threads which
64    checks that the balance of all accounts is invariant.  The idea for
65    this check is due to Bruno Haible.  */
66 #define N_ACCOUNT 8
67 #define ACCOUNT_VALUE 42
68 static int account[N_ACCOUNT];
69
70 /* Number of transactions done by each accountant.  */
71 #define N_TRANSACTIONS 1000
72
73 /* Number of accountants to run.  */
74 #define N_ACCOUNTANTS 5
75
76 /* Maximum transaction value.  A quite low value is used so that we
77    would get an integer overflow.  */
78 #define MAX_TRANSACTION_VALUE 50
79
80 /* Flag to tell the revision thread to finish.  */
81 static volatile int stop_revision_thread;
82
83
84 struct thread_arg_s
85 {
86   int no;
87 };
88
89
90
91 \f
92 /* Wrapper functions to access Libgcrypt's internal test lock.  */
93 static void
94 external_lock_test_init (int line)
95 {
96   gpg_error_t err;
97
98   err = gcry_control (PRIV_CTL_EXTERNAL_LOCK_TEST, EXTERNAL_LOCK_TEST_INIT);
99   if (err)
100     fail ("init lock failed at %d: %s", line, gpg_strerror (err));
101 }
102
103 static void
104 external_lock_test_lock (int line)
105 {
106   gpg_error_t err;
107
108   err = gcry_control (PRIV_CTL_EXTERNAL_LOCK_TEST, EXTERNAL_LOCK_TEST_LOCK);
109   if (err)
110     fail ("taking lock failed at %d: %s", line, gpg_strerror (err));
111 }
112
113 static void
114 external_lock_test_unlock (int line)
115 {
116   gpg_error_t err;
117
118   err = gcry_control (PRIV_CTL_EXTERNAL_LOCK_TEST, EXTERNAL_LOCK_TEST_UNLOCK);
119   if (err)
120     fail ("releasing lock failed at %d: %s", line, gpg_strerror (err));
121
122 }
123
124 static void
125 external_lock_test_destroy (int line)
126 {
127   gpg_error_t err;
128
129   err = gcry_control (PRIV_CTL_EXTERNAL_LOCK_TEST, EXTERNAL_LOCK_TEST_DESTROY);
130   if (err)
131     fail ("destroying lock failed at %d: %s", line, gpg_strerror (err));
132 }
133
134
135
136 \f
137 /* The nonce thread.  We simply request a couple of nonces and
138    return.  */
139 static THREAD_RET_TYPE
140 nonce_thread (void *argarg)
141 {
142   struct thread_arg_s *arg = argarg;
143   int i;
144   char nonce[NONCE_SIZE];
145
146   for (i = 0; i < N_NONCE_ITERATIONS; i++)
147     {
148       gcry_create_nonce (nonce, sizeof nonce);
149       if (i && !(i%100))
150         info ("thread %d created %d nonces so far", arg->no, i);
151     }
152
153   gcry_free (arg);
154   return THREAD_RET_VALUE;
155 }
156
157
158 /* To check our locking function we run several threads all accessing
159    the nonce functions.  If this function returns we know that there
160    are no obvious deadlocks or failed lock initialization.  */
161 static void
162 check_nonce_lock (void)
163 {
164   struct thread_arg_s *arg;
165 #ifdef _WIN32
166   HANDLE threads[N_NONCE_THREADS];
167   int i;
168   int rc;
169
170   for (i=0; i < N_NONCE_THREADS; i++)
171     {
172       arg = gcry_xmalloc (sizeof *arg);
173       arg->no = i;
174       threads[i] = CreateThread (NULL, 0, nonce_thread, arg, 0, NULL);
175       if (!threads[i])
176         die ("error creating nonce thread %d: rc=%d",
177              i, (int)GetLastError ());
178     }
179
180   for (i=0; i < N_NONCE_THREADS; i++)
181     {
182       rc = WaitForSingleObject (threads[i], INFINITE);
183       if (rc == WAIT_OBJECT_0)
184         info ("nonce thread %d has terminated", i);
185       else
186         fail ("waiting for nonce thread %d failed: %d",
187               i, (int)GetLastError ());
188       CloseHandle (threads[i]);
189     }
190
191 #elif HAVE_PTHREAD
192   pthread_t threads[N_NONCE_THREADS];
193   int rc, i;
194
195   for (i=0; i < N_NONCE_THREADS; i++)
196     {
197       arg = gcry_xmalloc (sizeof *arg);
198       arg->no = i;
199       pthread_create (&threads[i], NULL, nonce_thread, arg);
200     }
201
202   for (i=0; i < N_NONCE_THREADS; i++)
203     {
204       rc = pthread_join (threads[i], NULL);
205       if (rc)
206         fail ("pthread_join failed for nonce thread %d: %s",
207               i, strerror (errno));
208       else
209         info ("nonce thread %d has terminated", i);
210     }
211
212 #endif /*!_WIN32*/
213 }
214
215
216 /* Initialize all accounts.  */
217 static void
218 init_accounts (void)
219 {
220   int i;
221
222   for (i=0; i < N_ACCOUNT; i++)
223     account[i] = ACCOUNT_VALUE;
224 }
225
226
227 /* Check that the sum of all accounts matches the initial sum.  */
228 static void
229 check_accounts (void)
230 {
231   int i, sum;
232
233   sum = 0;
234   for (i = 0; i < N_ACCOUNT; i++)
235     sum += account[i];
236   if (sum != N_ACCOUNT * ACCOUNT_VALUE)
237     die ("accounts out of balance");
238 }
239
240
241 static void
242 print_accounts (void)
243 {
244   int i;
245
246   for (i=0; i < N_ACCOUNT; i++)
247     printf ("account %d: %6d\n", i, account[i]);
248 }
249
250
251 /* Get a a random integer value in the range 0 to HIGH.  */
252 static unsigned int
253 get_rand (int high)
254 {
255   return (unsigned int)(1+(int)((double)(high+1)*rand ()/(RAND_MAX+1.0))) - 1;
256 }
257
258
259 /* Pick a random account.  Note that this function is not
260    thread-safe. */
261 static int
262 pick_account (void)
263 {
264   return get_rand (N_ACCOUNT - 1);
265 }
266
267
268 /* Pick a random value for a transaction.  This is not thread-safe.  */
269 static int
270 pick_value (void)
271 {
272   return get_rand (MAX_TRANSACTION_VALUE);
273 }
274
275
276 /* This is the revision department.  */
277 static THREAD_RET_TYPE
278 revision_thread (void *arg)
279 {
280   (void)arg;
281
282   while (!stop_revision_thread)
283     {
284       external_lock_test_lock (__LINE__);
285       check_accounts ();
286       external_lock_test_unlock (__LINE__);
287     }
288   return THREAD_RET_VALUE;
289 }
290
291
292 /* This is one of our accountants.  */
293 static THREAD_RET_TYPE
294 accountant_thread (void *arg)
295 {
296   int i;
297   int acc1, acc2;
298   int value;
299
300   (void)arg;
301
302   for (i = 0; i < N_TRANSACTIONS; i++)
303     {
304       external_lock_test_lock (__LINE__);
305       acc1 = pick_account ();
306       acc2 = pick_account ();
307       value = pick_value ();
308       account[acc1] += value;
309       account[acc2] -= value;
310       external_lock_test_unlock (__LINE__);
311     }
312   return THREAD_RET_VALUE;
313 }
314
315
316 static void
317 run_test (void)
318 {
319 #ifdef _WIN32
320   HANDLE rthread;
321   HANDLE athreads[N_ACCOUNTANTS];
322   int i;
323   int rc;
324
325   external_lock_test_init (__LINE__);
326   stop_revision_thread = 0;
327   rthread = CreateThread (NULL, 0, revision_thread, NULL, 0, NULL);
328   if (!rthread)
329     die ("error creating revision thread: rc=%d", (int)GetLastError ());
330
331   for (i=0; i < N_ACCOUNTANTS; i++)
332     {
333       athreads[i] = CreateThread (NULL, 0, accountant_thread, NULL, 0, NULL);
334       if (!athreads[i])
335         die ("error creating accountant thread %d: rc=%d",
336              i, (int)GetLastError ());
337     }
338
339   for (i=0; i < N_ACCOUNTANTS; i++)
340     {
341       rc = WaitForSingleObject (athreads[i], INFINITE);
342       if (rc == WAIT_OBJECT_0)
343         info ("accountant thread %d has terminated", i);
344       else
345         fail ("waiting for accountant thread %d failed: %d",
346               i, (int)GetLastError ());
347       CloseHandle (athreads[i]);
348     }
349   stop_revision_thread = 1;
350
351   rc = WaitForSingleObject (rthread, INFINITE);
352   if (rc == WAIT_OBJECT_0)
353     info ("revision thread has terminated");
354   else
355     fail ("waiting for revision thread failed: %d", (int)GetLastError ());
356   CloseHandle (rthread);
357
358 #else /*!_WIN32*/
359   pthread_t rthread;
360   pthread_t athreads[N_ACCOUNTANTS];
361   int rc, i;
362
363   external_lock_test_init (__LINE__);
364   stop_revision_thread = 0;
365   pthread_create (&rthread, NULL, revision_thread, NULL);
366
367   for (i=0; i < N_ACCOUNTANTS; i++)
368     pthread_create (&athreads[i], NULL, accountant_thread, NULL);
369
370   for (i=0; i < N_ACCOUNTANTS; i++)
371     {
372       rc = pthread_join (athreads[i], NULL);
373       if (rc)
374         fail ("pthread_join failed for accountant thread %d: %s",
375               i, strerror (errno));
376       else
377         info ("accountant thread %d has terminated", i);
378     }
379
380   stop_revision_thread = 1;
381   rc = pthread_join (rthread, NULL);
382   if (rc)
383     fail ("pthread_join failed for the revision thread: %s", strerror (errno));
384   else
385     info ("revision thread has terminated");
386
387 #endif /*!_WIN32*/
388
389   external_lock_test_destroy (__LINE__);
390 }
391
392
393
394 int
395 main (int argc, char **argv)
396 {
397   int last_argc = -1;
398
399   if (argc)
400     {
401       argc--; argv++;
402     }
403   while (argc && last_argc != argc )
404     {
405       last_argc = argc;
406       if (!strcmp (*argv, "--help"))
407         {
408           puts (
409 "usage: ./t-lock [options]\n"
410 "\n"
411 "Options:\n"
412 "  --verbose      Show what is going on\n"
413 "  --debug        Flyswatter\n"
414 );
415           exit (0);
416         }
417       if (!strcmp (*argv, "--verbose"))
418         {
419           verbose = 1;
420           argc--; argv++;
421         }
422       else if (!strcmp (*argv, "--debug"))
423         {
424           verbose = debug = 1;
425           argc--; argv++;
426         }
427     }
428
429   srand (time(NULL)*getpid());
430
431   if (debug)
432     xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
433   xgcry_control (GCRYCTL_DISABLE_SECMEM, 0);
434   if (!gcry_check_version (GCRYPT_VERSION))
435     die ("version mismatch");
436   /* We are using non-public interfaces - check the exact version.  */
437   if (strcmp (gcry_check_version (NULL), GCRYPT_VERSION))
438     die ("exact version match failed");
439   xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
440   xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
441
442   check_nonce_lock ();
443
444   init_accounts ();
445   check_accounts ();
446
447   run_test ();
448   check_accounts ();
449
450   /* Run a second time to check deinit code.  */
451   run_test ();
452   check_accounts ();
453
454   if (verbose)
455     print_accounts ();
456
457   return error_count ? 1 : 0;
458 }