tests/: Include unistd.h on *NIX only
[platform/upstream/glib.git] / tests / slice-concurrent.c
1 /* test for gslice cross thread allocation/free
2  * Copyright (C) 2006 Stefan Westerfeld
3  * Copyright (C) 2007 Tim Janik
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 #include <glib.h>
21 #include <stdlib.h>
22 #ifdef G_OS_UNIX
23 #include <unistd.h>
24 #endif
25
26 #define N_THREADS       8
27 #define N_ALLOCS        50000
28 #define MAX_BLOCK_SIZE  64
29
30 struct ThreadData
31 {
32   int      thread_id;
33   GThread* gthread;
34
35   GMutex   to_free_mutex;
36   void*    to_free [N_THREADS * N_ALLOCS];
37   int      bytes_to_free [N_THREADS * N_ALLOCS];
38   int      n_to_free;
39   int      n_freed;
40 } tdata[N_THREADS];
41
42 static void *
43 thread_func (void *arg)
44 {
45   struct ThreadData *td = arg;
46   int i;
47 /*   g_print ("Thread %d starting\n", td->thread_id); */
48   for (i = 0; i < N_ALLOCS; i++)
49     {
50       int bytes;
51       char *mem;
52       int f;
53       int t;
54
55       if (rand() % (N_ALLOCS / 20) == 0)
56         g_print ("%c", 'a' - 1 + td->thread_id);
57
58       /* allocate block of random size and randomly fill */
59       bytes = rand() % MAX_BLOCK_SIZE + 1;
60       mem = g_slice_alloc (bytes);
61
62       for (f = 0; f < bytes; f++)
63         mem[f] = rand();
64
65       /* associate block with random thread */
66       t = rand() % N_THREADS;
67       g_mutex_lock (&tdata[t].to_free_mutex);
68       tdata[t].to_free[tdata[t].n_to_free] = mem;
69       tdata[t].bytes_to_free[tdata[t].n_to_free] = bytes;
70       tdata[t].n_to_free++;
71       g_mutex_unlock (&tdata[t].to_free_mutex);
72
73       /* shuffle thread execution order every once in a while */
74       if (rand() % 97 == 0)
75         {
76           if (rand() % 2)
77             g_thread_yield();   /* concurrent shuffling for single core */
78           else
79             g_usleep (1000);    /* concurrent shuffling for multi core */
80         }
81
82       /* free a block associated with this thread */
83       g_mutex_lock (&td->to_free_mutex);
84       if (td->n_to_free > 0)
85         {
86           td->n_to_free--;
87           g_slice_free1 (td->bytes_to_free[td->n_to_free], td->to_free[td->n_to_free]);
88           td->n_freed++;
89         }
90       g_mutex_unlock (&td->to_free_mutex);
91     }
92
93   return NULL;
94 }
95
96 int
97 main (void)
98 {
99   int t;
100
101   for (t = 0; t < N_THREADS; t++)
102     {
103       tdata[t].thread_id = t + 1;
104       tdata[t].n_to_free = 0;
105       tdata[t].n_freed = 0;
106     }
107   g_print ("Starting %d threads for concurrent GSlice usage...\n", N_THREADS);
108   for (t = 0; t < N_THREADS; t++)
109     {
110       tdata[t].gthread   = g_thread_create (thread_func, &tdata[t], TRUE, NULL);
111       g_assert (tdata[t].gthread != NULL);
112     }
113   for (t = 0; t < N_THREADS; t++)
114     {
115       g_thread_join (tdata[t].gthread);
116     }
117   g_print ("\n");
118   for (t = 0; t < N_THREADS; t++)
119     {
120       g_print ("Thread %d: %d blocks freed, %d blocks not freed\n",
121                     tdata[t].thread_id, tdata[t].n_freed, tdata[t].n_to_free);
122     }
123   return 0;
124 }