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