Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #include <kdb.h>
10 : #include <kdbhelper.h>
11 : #include <kdbmacros.h>
12 :
13 : #include <fcntl.h>
14 : #include <pthread.h>
15 : #include <stdio.h>
16 : #include <stdlib.h>
17 : #include <sys/mman.h>
18 : #include <sys/stat.h>
19 : #include <sys/wait.h>
20 : #include <unistd.h>
21 :
22 : pthread_barrier_t * bar;
23 :
24 0 : void * writer (void * pV_data ELEKTRA_UNUSED)
25 : {
26 0 : Key * parent = keyNew ("user/test/race", KEY_END);
27 0 : KDB * h = kdbOpen (parent);
28 : char buffer[4096];
29 0 : unsigned long tid = (unsigned long) pthread_self ();
30 0 : int pid = getpid ();
31 0 : sprintf (buffer, "user/test/race/keys/%d/%lu", pid, tid);
32 0 : KeySet * ks = ksNew (20, KS_END);
33 :
34 0 : int retg = kdbGet (h, ks, parent);
35 0 : ksAppendKey (ks, keyNew (buffer, KEY_VALUE, "a value", KEY_END));
36 :
37 0 : pthread_barrier_wait (bar);
38 0 : int rets = kdbSet (h, ks, parent);
39 :
40 0 : if (rets != -1)
41 : {
42 0 : int retg2 = kdbGet (h, ks, parent);
43 0 : printf ("I (%d/%lu) won the race! Got return values from first get %d,"
44 : " from set %d, from second get %d\n",
45 : pid, tid, retg, rets, retg2);
46 0 : ksRewind (ks);
47 : /*
48 : Key * c;
49 : while ((c = ksNext(ks)))
50 : {
51 : printf ("Got key: %s - %s\n",
52 : keyName(c), keyString(c));
53 : }
54 : */
55 : }
56 : else
57 : {
58 0 : printf ("I (%d/%lu) lost the race! Got %d and from set %d\n", pid, tid, retg, rets);
59 : }
60 :
61 0 : ksDel (ks);
62 0 : kdbClose (h, parent);
63 0 : keyDel (parent);
64 :
65 : // pthread_exit (NULL);
66 0 : return 0;
67 : }
68 :
69 0 : int main (int argc, char ** argv)
70 : {
71 0 : if (argc != 4)
72 : {
73 0 : printf ("Usage %s <procs> <threads> <barriers>\n", argv[0]);
74 0 : printf ("This program tests race condition in Elektra\n");
75 0 : printf ("If you set barriers procs*threads, all threads will\n");
76 0 : printf ("start kdbSet() at roughly the same time\n");
77 0 : return 1;
78 : }
79 :
80 : // on error (0) is safe
81 0 : int num_procs = atoi (argv[1]);
82 0 : int num_threads = atoi (argv[2]);
83 0 : int num_barriers = atoi (argv[3]);
84 :
85 0 : if (num_barriers > num_procs * num_threads)
86 : {
87 : return 1;
88 : }
89 :
90 : pthread_barrierattr_t attr;
91 0 : if (pthread_barrierattr_init (&attr) != 0)
92 : {
93 : return 2;
94 : }
95 :
96 0 : if (pthread_barrierattr_setpshared (&attr, PTHREAD_PROCESS_SHARED) != 0)
97 : {
98 : return 3;
99 : }
100 :
101 0 : char shm_name[] = "shm_name_elektra_test_race";
102 0 : shm_unlink (shm_name); // may fail
103 :
104 0 : int shm_fd = shm_open (shm_name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
105 :
106 0 : if (shm_fd == -1)
107 : {
108 : return 6;
109 : }
110 :
111 0 : if (ftruncate (shm_fd, sizeof (pthread_barrier_t)) != 0)
112 : {
113 : return 7;
114 : }
115 :
116 0 : bar = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
117 :
118 0 : if (bar == MAP_FAILED)
119 : {
120 0 : shm_unlink (shm_name);
121 0 : return 8;
122 : }
123 :
124 0 : if (pthread_barrier_init (bar, &attr, num_barriers) != 0)
125 : {
126 : return 10;
127 : }
128 :
129 0 : if (pthread_barrierattr_destroy (&attr) != 0)
130 : {
131 : return 11;
132 : }
133 :
134 :
135 : int i;
136 0 : for (i = 0; i < num_procs; i++)
137 : {
138 0 : int pid = fork ();
139 :
140 0 : if (pid == -1)
141 : {
142 : // fork not successful
143 : return 12;
144 : }
145 0 : else if (pid == 0)
146 : {
147 : // child
148 0 : pthread_t * pwriter = elektraMalloc (num_threads * sizeof (pthread_t));
149 0 : if (!pwriter) return 13;
150 0 : for (i = 0; i < num_threads; i++)
151 0 : if (pthread_create (&pwriter[i], NULL, writer, (void *) 0) != 0) return 14;
152 0 : for (i = 0; i < num_threads; i++)
153 0 : pthread_join (pwriter[i], NULL);
154 0 : elektraFree (pwriter);
155 0 : return 0;
156 : }
157 : }
158 :
159 0 : int status = 0;
160 0 : int sumexitstatus = 0;
161 0 : for (i = 0; i < num_procs; i++)
162 : {
163 0 : wait (&status);
164 0 : int exitstatus = WEXITSTATUS (status);
165 :
166 0 : if (exitstatus)
167 : {
168 0 : sumexitstatus = 100 + exitstatus;
169 : }
170 : }
171 :
172 :
173 0 : if (pthread_barrier_destroy (bar) != 0)
174 : {
175 : return 40;
176 : }
177 :
178 0 : if ((shm_unlink (shm_name)) != 0)
179 : {
180 : return 41;
181 : }
182 :
183 0 : printf ("Test run finished\n");
184 0 : return sumexitstatus;
185 : }
|