1 /* $OpenBSD: pthread_rwlock2.c,v 1.1 2019/03/04 08:23:05 semarie Exp $ */
2 /*
3  * Copyright (c) 2019 Sebastien Marie <semarie@online.fr>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <err.h>
19 #include <pthread.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #define LOOP_MAIN	64	/* number of loop to try */
25 #define NTHREADS	16	/* number of concurrents threads */
26 
27 /*
28  * start several threads that share a buffer protected by rwlock.
29  *
30  * for each thread, take lock rw to set the buffer, and next take lock
31  * rd to read (print) the buffer content.
32  */
33 
34 static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
35 static char msg[128] = "default message";
36 
37 void
set_msg(int self_n,char * new_msg)38 set_msg(int self_n, char *new_msg)
39 {
40 	pthread_t self = pthread_self();
41 
42 	if (pthread_rwlock_wrlock(&rwlock) != 0)
43 		err(EXIT_FAILURE, "set_msg: pthread_rwlock_wrlock");
44 
45 	printf("%p: %d: set_msg\n", self, self_n);
46 	strlcpy(msg, new_msg, sizeof(msg));
47 
48 	if (pthread_rwlock_unlock(&rwlock) != 0)
49 		err(EXIT_FAILURE, "set_msg: pthread_rwlock_unlock");
50 }
51 
52 void
print_msg(int self_n)53 print_msg(int self_n)
54 {
55 	pthread_t self = pthread_self();
56 
57 	if (pthread_rwlock_rdlock(&rwlock) != 0)
58 		err(EXIT_FAILURE, "print_msg: pthread_rwlock_rdlock");
59 
60 	printf("%p: %d: msg: \"%s\"\n", self, self_n, msg);
61 
62 	if (pthread_rwlock_unlock(&rwlock) != 0)
63 		err(EXIT_FAILURE, "print_msg: pthread_rwlock_unlock");
64 }
65 
66 void *
run(void * data)67 run(void *data)
68 {
69 	int self_n = (int)data;
70 	pthread_t self = pthread_self();
71 
72 	printf("%p: %d: enter run()\n", self, self_n);
73 
74 	set_msg(self_n, "new message");
75 	print_msg(self_n);
76 
77 	printf("%p: %d: exit run()\n", self, self_n);
78 	return NULL;
79 }
80 
81 int
main(int argc,char * argv[])82 main(int argc, char *argv[])
83 {
84 	int i, j;
85 
86 	/* enable some rthread debug code (env take precedence) */
87 	if (setenv("RTHREAD_DEBUG", "9", 0) == -1)
88 		err(EXIT_FAILURE, "setenv");
89 
90 	/* test in loop */
91 	for (i=0; i < LOOP_MAIN; i++) {
92 		pthread_t handlers[NTHREADS];
93 
94 		printf("main: %d\n", i);
95 
96 		/* launch a serie of threads */
97 		for (j=0; j < NTHREADS; j++) {
98 			if (pthread_create(&(handlers[j]), NULL,
99 			    &run, (void *)(long)j) != 0)
100 				err(EXIT_FAILURE, "main: pthread_create");
101 		}
102 
103 		/* wait for them to finish */
104 		for (j=0; j < NTHREADS; j++) {
105 			if (pthread_join(handlers[j], NULL) != 0)
106 				err(EXIT_FAILURE, "main: pthread_join");
107 		}
108 	}
109 
110 	return EXIT_SUCCESS;
111 }
112