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