xref: /aosp_15_r20/external/ltp/testcases/open_posix_testsuite/stress/threads/pthread_mutex_lock/stress.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 /*
2  * Copyright (c) 2004, Bull S.A..  All rights reserved.
3  * Created by: Sebastien Decugis
4 
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write the Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  *
17 
18  * This file is a stress test for the pthread_mutex_lock function.
19 
20  * The steps are:
21  * -> For each king of mutex, we create 10*F threads (F is a scalability factor)
22  * -> we call those threads 1 to 10.
23  *    -> thread 1 sends signal USR2 to the other 9 threads (which have a handler for it)
24  *    -> thread 2 to 6 are loops
25  *          {
26  *               mutex_lock
27  *               if (ctrl) exit
28  *               ctrl = 1
29  *               yield
30  *               ctrl= 0
31  *               mutex unlock
32  *          }
33  *     -> thread 7 & 8 have a timedlock instead of lock
34  *     -> thread 9 & 10 have a trylock instead of lock
35  *
36  * -> the whole process stop when receiving signal SIGUSR1.
37  *      This goal is achieved with a "do_it" variable.
38  *
39  * NOTE: With gcc/linux, the flag "-lrt" must be specified at link time.
40  */
41 
42 /********************************************************************************************/
43 /****************************** standard includes *****************************************/
44 /********************************************************************************************/
45 #include <pthread.h>
46 #include <errno.h>
47 #include <semaphore.h>
48 #include <signal.h>
49 #include <unistd.h>
50 #if _POSIX_TIMEOUTS < 0
51 #error "This sample needs POSIX TIMEOUTS option support"
52 #endif
53 #if _POSIX_TIMEOUTS == 0
54 #warning "This sample needs POSIX TIMEOUTS option support"
55 #endif
56 #if _POSIX_TIMERS < 0
57 #error "This sample needs POSIX TIMERS option support"
58 #endif
59 #if _POSIX_TIMERS == 0
60 #warning "This sample needs POSIX TIMERS option support"
61 #endif
62 
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <stdarg.h>
66 #include <time.h>		/* required for the pthread_mutex_timedlock() function */
67 
68 /********************************************************************************************/
69 /******************************   Test framework   *****************************************/
70 /********************************************************************************************/
71 #include "testfrmw.h"
72 #include "testfrmw.c"
73  /* This header is responsible for defining the following macros:
74   * UNRESOLVED(ret, descr);
75   *    where descr is a description of the error and ret is an int (error code for example)
76   * FAILED(descr);
77   *    where descr is a short text saying why the test has failed.
78   * PASSED();
79   *    No parameter.
80   *
81   * Both three macros shall terminate the calling process.
82   * The testcase shall not terminate in any other maneer.
83   *
84   * The other file defines the functions
85   * void output_init()
86   * void output(char * string, ...)
87   *
88   * Those may be used to output information.
89   */
90 
91 /********************************************************************************************/
92 /********************************** Configuration ******************************************/
93 /********************************************************************************************/
94 #ifndef SCALABILITY_FACTOR
95 #define SCALABILITY_FACTOR 1
96 #endif
97 #ifndef VERBOSE
98 #define VERBOSE 2
99 #endif
100 #define N 2			/* N * 10 * 6 * SCALABILITY_FACTOR threads will be created */
101 
102 /********************************************************************************************/
103 /***********************************    Test case   *****************************************/
104 /********************************************************************************************/
105 static char do_it = 1;
106 #ifndef WITHOUT_XOPEN
107 static int types[] = { PTHREAD_MUTEX_NORMAL,
108 	PTHREAD_MUTEX_ERRORCHECK,
109 	PTHREAD_MUTEX_RECURSIVE,
110 	PTHREAD_MUTEX_DEFAULT
111 };
112 #endif
113 
114 /* The following type represents the data
115  * for one group of ten threads */
116 typedef struct {
117 	pthread_t threads[10];	/* The 10 threads */
118 	pthread_mutex_t mtx;	/* The mutex those threads work on */
119 	char ctrl;		/* The value used to check the behavior */
120 	char sigok;		/* Used to tell the threads they can return */
121 	sem_t semsig;		/* Semaphore for synchronizing the signal handler */
122 	int id;			/* An identifier for the threads group */
123 	int tcnt;		/* we need to make sure the threads are started before killing 'em */
124 	pthread_mutex_t tmtx;
125 	unsigned long long sigcnt, opcnt;	/* We count every iteration */
126 } cell_t;
127 
128 static pthread_key_t _c;		/* this key will always contain a pointer to the thread's cell */
129 
130 /***** The next function is in charge of sending signal USR2 to
131  * all the other threads in its cell, until the end of the test. */
sigthr(void * arg)132 static void *sigthr(void *arg)
133 {
134 	int ret;
135 	int i = 0;
136 	cell_t *c = (cell_t *) arg;
137 
138 	do {
139 		sched_yield();
140 		ret = pthread_mutex_lock(&(c->tmtx));
141 		if (ret != 0) {
142 			UNRESOLVED(ret, "Failed to lock the mutex");
143 		}
144 		i = c->tcnt;
145 		ret = pthread_mutex_unlock(&(c->tmtx));
146 		if (ret != 0) {
147 			UNRESOLVED(ret, "Failed to unlock the mutex");
148 		}
149 	} while (i < 9);
150 
151 	/* Until we must stop, do */
152 	while (do_it) {
153 		/* Wait for the semaphore */
154 		ret = sem_wait(&(c->semsig));
155 		if (ret != 0) {
156 			UNRESOLVED(errno, "Sem wait failed in signal thread");
157 		}
158 
159 		/* Kill the next thread */
160 		i %= 9;
161 		ret = pthread_kill(c->threads[++i], SIGUSR2);
162 		if (ret != 0) {
163 			UNRESOLVED(ret, "Thread kill failed in signal thread");
164 		}
165 
166 		/* Increment the signal counter */
167 		c->sigcnt++;
168 	}
169 
170 	/* Tell the other threads they can now stop */
171 	do {
172 		c->sigok = 1;
173 	}
174 	while (c->sigok == 0);
175 
176 	return NULL;
177 }
178 
179 /***** The next function is the signal handler
180  * for all the others threads in the cell */
sighdl(int sig)181 static void sighdl(int sig)
182 {
183 	int ret;
184 	cell_t *c = (cell_t *) pthread_getspecific(_c);
185 	ret = sem_post(&(c->semsig));
186 	if (ret != 0) {
187 		UNRESOLVED(errno, "Unable to post semaphore in signal handler");
188 	}
189 }
190 
191 /***** The next function can return only when the sigthr has terminated.
192  * This avoids the signal thread try to kill a terminated thread. */
waitsigend(cell_t * c)193 static void waitsigend(cell_t * c)
194 {
195 	while (c->sigok == 0) {
196 		sched_yield();
197 	}
198 }
199 
200 /***** The next function aims to control that no other thread
201  * owns the mutex at the same time */
control(cell_t * c,char * loc)202 static void control(cell_t * c, char *loc)
203 {
204 	*loc++;			/* change the local control value */
205 	if (c->ctrl != 0) {
206 		FAILED("Got a non-zero value - two threads owns the mutex");
207 	}
208 	c->ctrl = *loc;
209 	sched_yield();
210 	if (c->ctrl != *loc) {
211 		FAILED
212 		    ("Got a different value - another thread touched protected data");
213 	}
214 	c->ctrl = 0;
215 
216 	/* Avoid some values for the next control */
217 	if (*loc == 120)
218 		*loc = -120;
219 	if (*loc == -1)
220 		*loc = 1;
221 }
222 
223 /***** The next 3 functions are the worker threads
224  */
lockthr(void * arg)225 static void *lockthr(void *arg)
226 {
227 	int ret;
228 	char loc;		/* Local value for control */
229 	cell_t *c = (cell_t *) arg;
230 
231 	/* Set the thread local data key value (used in the signal handler) */
232 	ret = pthread_setspecific(_c, arg);
233 	if (ret != 0) {
234 		UNRESOLVED(ret, "Unable to assign the thread-local-data key");
235 	}
236 
237 	/* Signal we're started */
238 	ret = pthread_mutex_lock(&(c->tmtx));
239 	if (ret != 0) {
240 		UNRESOLVED(ret, "Failed to lock the mutex");
241 	}
242 	c->tcnt += 1;
243 	ret = pthread_mutex_unlock(&(c->tmtx));
244 	if (ret != 0) {
245 		UNRESOLVED(ret, "Failed to unlock the mutex");
246 	}
247 
248 	do {
249 		/* Lock, control, then unlock */
250 		ret = pthread_mutex_lock(&(c->mtx));
251 		if (ret != 0) {
252 			UNRESOLVED(ret, "Mutex lock failed in worker thread");
253 		}
254 
255 		control(c, &loc);
256 
257 		ret = pthread_mutex_unlock(&(c->mtx));
258 		if (ret != 0) {
259 			UNRESOLVED(ret, "Mutex unlock failed in worker thread");
260 		}
261 
262 		/* Increment the operation counter */
263 		c->opcnt++;
264 	}
265 	while (do_it);
266 
267 	/* Wait for the signal thread to terminate before we can exit */
268 	waitsigend(c);
269 	return NULL;
270 }
271 
timedlockthr(void * arg)272 static void *timedlockthr(void *arg)
273 {
274 	int ret;
275 	char loc;		/* Local value for control */
276 	struct timespec ts;
277 	cell_t *c = (cell_t *) arg;
278 
279 	/* Set the thread local data key value (used in the signal handler) */
280 	ret = pthread_setspecific(_c, arg);
281 	if (ret != 0) {
282 		UNRESOLVED(ret, "Unable to assign the thread-local-data key");
283 	}
284 
285 	/* Signal we're started */
286 	ret = pthread_mutex_lock(&(c->tmtx));
287 	if (ret != 0) {
288 		UNRESOLVED(ret, "Failed to lock the mutex");
289 	}
290 	c->tcnt += 1;
291 	ret = pthread_mutex_unlock(&(c->tmtx));
292 	if (ret != 0) {
293 		UNRESOLVED(ret, "Failed to unlock the mutex");
294 	}
295 
296 	do {
297 		/* Lock, control, then unlock */
298 		do {
299 			ret = clock_gettime(CLOCK_REALTIME, &ts);
300 			if (ret != 0) {
301 				UNRESOLVED(errno,
302 					   "Unable to get time for timeout");
303 			}
304 			ts.tv_sec++;	/* We will wait for 1 second */
305 			ret = pthread_mutex_timedlock(&(c->mtx), &ts);
306 		} while (ret == ETIMEDOUT);
307 		if (ret != 0) {
308 			UNRESOLVED(ret,
309 				   "Timed mutex lock failed in worker thread");
310 		}
311 
312 		control(c, &loc);
313 
314 		ret = pthread_mutex_unlock(&(c->mtx));
315 		if (ret != 0) {
316 			UNRESOLVED(ret, "Mutex unlock failed in worker thread");
317 		}
318 
319 		/* Increment the operation counter */
320 		c->opcnt++;
321 	}
322 	while (do_it);
323 
324 	/* Wait for the signal thread to terminate before we can exit */
325 	waitsigend(c);
326 	return NULL;
327 }
328 
trylockthr(void * arg)329 static void *trylockthr(void *arg)
330 {
331 	int ret;
332 	char loc;		/* Local value for control */
333 	cell_t *c = (cell_t *) arg;
334 
335 	/* Set the thread local data key value (used in the signal handler) */
336 	ret = pthread_setspecific(_c, arg);
337 	if (ret != 0) {
338 		UNRESOLVED(ret, "Unable to assign the thread-local-data key");
339 	}
340 
341 	/* Signal we're started */
342 	ret = pthread_mutex_lock(&(c->tmtx));
343 	if (ret != 0) {
344 		UNRESOLVED(ret, "Failed to lock the mutex");
345 	}
346 	c->tcnt += 1;
347 	ret = pthread_mutex_unlock(&(c->tmtx));
348 	if (ret != 0) {
349 		UNRESOLVED(ret, "Failed to unlock the mutex");
350 	}
351 
352 	do {
353 		/* Lock, control, then unlock */
354 		do {
355 			ret = pthread_mutex_trylock(&(c->mtx));
356 		} while (ret == EBUSY);
357 		if (ret != 0) {
358 			UNRESOLVED(ret,
359 				   "Mutex lock try failed in worker thread");
360 		}
361 
362 		control(c, &loc);
363 
364 		ret = pthread_mutex_unlock(&(c->mtx));
365 		if (ret != 0) {
366 			UNRESOLVED(ret, "Mutex unlock failed in worker thread");
367 		}
368 
369 		/* Increment the operation counter */
370 		c->opcnt++;
371 	}
372 	while (do_it);
373 
374 	/* Wait for the signal thread to terminate before we can exit */
375 	waitsigend(c);
376 	return NULL;
377 }
378 
379 /***** The next function initializes a cell_t object
380  * This includes running the threads */
cell_init(int id,cell_t * c,pthread_mutexattr_t * pma)381 static void cell_init(int id, cell_t * c, pthread_mutexattr_t * pma)
382 {
383 	int ret, i;
384 	pthread_attr_t pa;	/* We will specify a minimal stack size */
385 
386 	/* mark this group with its ID */
387 	c->id = id;
388 	/* Initialize some other values */
389 	c->sigok = 0;
390 	c->ctrl = 0;
391 	c->sigcnt = 0;
392 	c->opcnt = 0;
393 	c->tcnt = 0;
394 
395 	/* Initialize the mutex */
396 	ret = pthread_mutex_init(&(c->tmtx), NULL);
397 	if (ret != 0) {
398 		UNRESOLVED(ret, "Mutex init failed");
399 	}
400 	ret = pthread_mutex_init(&(c->mtx), pma);
401 	if (ret != 0) {
402 		UNRESOLVED(ret, "Mutex init failed");
403 	}
404 #if VERBOSE > 1
405 	output("Mutex initialized in cell %i\n", id);
406 #endif
407 
408 	/* Initialize the semaphore */
409 	ret = sem_init(&(c->semsig), 0, 0);
410 	if (ret != 0) {
411 		UNRESOLVED(errno, "Sem init failed");
412 	}
413 #if VERBOSE > 1
414 	output("Semaphore initialized in cell %i\n", id);
415 #endif
416 
417 	/* Create the thread attribute with the minimal size */
418 	ret = pthread_attr_init(&pa);
419 	if (ret != 0) {
420 		UNRESOLVED(ret, "Unable to create pthread attribute object");
421 	}
422 	ret = pthread_attr_setstacksize(&pa, sysconf(_SC_THREAD_STACK_MIN));
423 	if (ret != 0) {
424 		UNRESOLVED(ret, "Unable to specify minimal stack size");
425 	}
426 
427 	/* Create the signal thread */
428 	ret = pthread_create(&(c->threads[0]), &pa, sigthr, (void *)c);
429 	if (ret != 0) {
430 		UNRESOLVED(ret, "Unable to create the signal thread");
431 	}
432 
433 	/* Create 5 "lock" threads */
434 	for (i = 1; i <= 5; i++) {
435 		ret = pthread_create(&(c->threads[i]), &pa, lockthr, (void *)c);
436 		if (ret != 0) {
437 			UNRESOLVED(ret, "Unable to create a locker thread");
438 		}
439 	}
440 
441 	/* Create 2 "timedlock" threads */
442 	for (i = 6; i <= 7; i++) {
443 		ret =
444 		    pthread_create(&(c->threads[i]), &pa, timedlockthr,
445 				   (void *)c);
446 		if (ret != 0) {
447 			UNRESOLVED(ret,
448 				   "Unable to create a (timed) locker thread");
449 		}
450 	}
451 
452 	/* Create 2 "trylock" threads */
453 	for (i = 8; i <= 9; i++) {
454 		ret =
455 		    pthread_create(&(c->threads[i]), &pa, trylockthr,
456 				   (void *)c);
457 		if (ret != 0) {
458 			UNRESOLVED(ret,
459 				   "Unable to create a (try) locker thread");
460 		}
461 	}
462 
463 #if VERBOSE > 1
464 	output("All threads initialized in cell %i\n", id);
465 #endif
466 
467 	/* Destroy the thread attribute object */
468 	ret = pthread_attr_destroy(&pa);
469 	if (ret != 0) {
470 		UNRESOLVED(ret, "Unable to destroy thread attribute object");
471 	}
472 
473 	/* Tell the signal thread to start working */
474 	ret = sem_post(&(c->semsig));
475 	if (ret != 0) {
476 		UNRESOLVED(ret, "Unable to post signal semaphore");
477 	}
478 }
479 
480 /***** The next function destroys a cell_t object
481  * This includes stopping the threads */
cell_fini(int id,cell_t * c,unsigned long long * globalopcount,unsigned long long * globalsigcount)482 static void cell_fini(int id,
483 	       cell_t * c,
484 	       unsigned long long *globalopcount,
485 	       unsigned long long *globalsigcount)
486 {
487 	int ret, i;
488 
489 	/* Just a basic check */
490 	if (id != c->id) {
491 		output("Something is wrong: Cell %i has id %i\n", id, c->id);
492 		FAILED("Some memory has been corrupted");
493 	}
494 
495 	/* Start with joining the threads */
496 	for (i = 0; i < 10; i++) {
497 		ret = pthread_join(c->threads[i], NULL);
498 		if (ret != 0) {
499 			UNRESOLVED(ret, "Unable to join a thread");
500 		}
501 	}
502 
503 	/* Destroy the semaphore and the mutex */
504 	ret = sem_destroy(&(c->semsig));
505 	if (ret != 0) {
506 		UNRESOLVED(errno, "Unable to destroy the semaphore");
507 	}
508 
509 	ret = pthread_mutex_destroy(&(c->mtx));
510 	if (ret != 0) {
511 		output("Unable to destroy the mutex in cell %i (ret = %i)\n",
512 		       id, ret);
513 		FAILED("Mutex destruction failed");
514 	}
515 
516 	/* Report the cell counters */
517 	*globalopcount += c->opcnt;
518 	*globalsigcount += c->sigcnt;
519 #if VERBOSE > 1
520 	output
521 	    ("Counters for cell %i:\n\t%llu locks and unlocks\n\t%llu signals\n",
522 	     id, c->opcnt, c->sigcnt);
523 #endif
524 
525 	/* We are done with this cell. */
526 }
527 
528 /**** Next function is called when the process is killed with SIGUSR1
529  * It tells every threads in every cells to stop their work.
530  */
globalsig(int sig)531 static void globalsig(int sig)
532 {
533 	output("Signal received, processing. Please wait...\n");
534 	do {
535 		do_it = 0;
536 	}
537 	while (do_it);
538 }
539 
540 /******
541  * Last but not least, the main function
542  */
main(int argc,char * argv[])543 int main(int argc, char *argv[])
544 {
545 	/* Main is responsible for :
546 	 * the mutex attributes initializing
547 	 * the creation of the cells
548 	 * the destruction of everything on SIGUSR1 reception
549 	 */
550 
551 	int ret;
552 	int i;
553 	struct sigaction sa;
554 	unsigned long long globopcnt = 0, globsigcnt = 0;
555 
556 #ifndef WITHOUT_XOPEN
557 	int sz = 2 + (sizeof(types) / sizeof(int));
558 #else
559 	int sz = 2;
560 #endif
561 	pthread_mutexattr_t ma[sz - 1];
562 	pthread_mutexattr_t *pma[sz];
563 
564 	cell_t data[sz * N * SCALABILITY_FACTOR];
565 
566 	pma[sz - 1] = NULL;
567 
568 #if VERBOSE > 0
569 	output("Mutex lock / unlock stress sample is starting\n");
570 	output("Kill with SIGUSR1 to stop the process\n");
571 	output("\t kill -USR1 <pid>\n\n");
572 #endif
573 
574 	/* Initialize the mutex attributes */
575 	for (i = 0; i < sz - 1; i++) {
576 		pma[i] = &ma[i];
577 		ret = pthread_mutexattr_init(pma[i]);
578 		if (ret != 0) {
579 			UNRESOLVED(ret,
580 				   "Unable to init a mutex attribute object");
581 		}
582 #ifndef WITHOUT_XOPEN		/* we have the mutex attribute types */
583 		if (i != 0) {
584 			ret = pthread_mutexattr_settype(pma[i], types[i - 1]);
585 			if (ret != 0) {
586 				UNRESOLVED(ret,
587 					   "Unable to set type of a mutex attribute object");
588 			}
589 		}
590 #endif
591 	}
592 #if VERBOSE > 1
593 	output("%i mutex attribute objects were initialized\n", sz - 1);
594 #endif
595 
596 	/* Initialize the thread-local-data key */
597 	ret = pthread_key_create(&_c, NULL);
598 	if (ret != 0) {
599 		UNRESOLVED(ret, "Unable to initialize TLD key");
600 	}
601 #if VERBOSE > 1
602 	output("TLD key initialized\n");
603 #endif
604 
605 	/* Register the signal handler for SIGUSR1  */
606 	sigemptyset(&sa.sa_mask);
607 	sa.sa_flags = 0;
608 	sa.sa_handler = globalsig;
609 	if ((ret = sigaction(SIGUSR1, &sa, NULL))) {
610 		UNRESOLVED(ret, "Unable to register signal handler");
611 	}
612 
613 	/* Register the signal handler for SIGUSR2  */
614 	sa.sa_handler = sighdl;
615 	if ((ret = sigaction(SIGUSR2, &sa, NULL))) {
616 		UNRESOLVED(ret, "Unable to register signal handler");
617 	}
618 
619 	/* Start every threads */
620 #if VERBOSE > 0
621 	output("%i cells of 10 threads are being created...\n",
622 	       sz * N * SCALABILITY_FACTOR);
623 #endif
624 	for (i = 0; i < sz * N * SCALABILITY_FACTOR; i++)
625 		cell_init(i, &data[i], pma[i % sz]);
626 #if VERBOSE > 0
627 	output("All threads created and running.\n");
628 #endif
629 
630 	/* We stay here while not interrupted */
631 	do {
632 		sched_yield();
633 	}
634 	while (do_it);
635 
636 #if VERBOSE > 0
637 	output("Starting to join the threads...\n");
638 #endif
639 	/* Everybody is stopping, we must join them, and destroy the cell data */
640 	for (i = 0; i < sz * N * SCALABILITY_FACTOR; i++)
641 		cell_fini(i, &data[i], &globopcnt, &globsigcnt);
642 
643 	/* Destroy the mutex attributes objects */
644 	for (i = 0; i < sz - 1; i++) {
645 		ret = pthread_mutexattr_destroy(pma[i]);
646 		if (ret != 0) {
647 			UNRESOLVED(ret,
648 				   "Unable to destroy a mutex attribute object");
649 		}
650 	}
651 
652 	/* Destroy the thread-local-data key */
653 	ret = pthread_key_delete(_c);
654 	if (ret != 0) {
655 		UNRESOLVED(ret, "Unable to destroy TLD key");
656 	}
657 #if VERBOSE > 1
658 	output("TLD key destroyed\n");
659 #endif
660 
661 	/* output the total counters */
662 #if VERBOSE > 1
663 	output("===============================================\n");
664 #endif
665 #if VERBOSE > 0
666 	output("Total counters:\n\t%llu locks and unlocks\n\t%llu signals\n",
667 	       globopcnt, globsigcnt);
668 	output("pthread_mutex_lock stress test passed.\n");
669 #endif
670 
671 	PASSED;
672 }
673