1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0.  If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 
18 #include <isc/print.h>
19 #include <isc/rwlock.h>
20 #include <isc/string.h>
21 #include <isc/thread.h>
22 #include <isc/util.h>
23 
24 #ifdef WIN32
25 #define sleep(x) Sleep(1000 * x)
26 #endif /* ifdef WIN32 */
27 
28 isc_rwlock_t lock;
29 
30 static isc_threadresult_t
31 #ifdef WIN32
32 	WINAPI
33 #endif /* ifdef WIN32 */
run1(void * arg)34 	run1(void *arg) {
35 	char *message = arg;
36 
37 	RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_read) ==
38 		      ISC_R_SUCCESS);
39 	printf("%s got READ lock\n", message);
40 	sleep(1);
41 	printf("%s giving up READ lock\n", message);
42 	RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_read) ==
43 		      ISC_R_SUCCESS);
44 	RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_read) ==
45 		      ISC_R_SUCCESS);
46 	printf("%s got READ lock\n", message);
47 	sleep(1);
48 	printf("%s giving up READ lock\n", message);
49 	RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_read) ==
50 		      ISC_R_SUCCESS);
51 	RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_write) ==
52 		      ISC_R_SUCCESS);
53 	printf("%s got WRITE lock\n", message);
54 	sleep(1);
55 	printf("%s giving up WRITE lock\n", message);
56 	RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_write) ==
57 		      ISC_R_SUCCESS);
58 	return ((isc_threadresult_t)0);
59 }
60 
61 static isc_threadresult_t
62 #ifdef WIN32
63 	WINAPI
64 #endif /* ifdef WIN32 */
run2(void * arg)65 	run2(void *arg) {
66 	char *message = arg;
67 
68 	RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_write) ==
69 		      ISC_R_SUCCESS);
70 	printf("%s got WRITE lock\n", message);
71 	sleep(1);
72 	printf("%s giving up WRITE lock\n", message);
73 	RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_write) ==
74 		      ISC_R_SUCCESS);
75 	RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_write) ==
76 		      ISC_R_SUCCESS);
77 	printf("%s got WRITE lock\n", message);
78 	sleep(1);
79 	printf("%s giving up WRITE lock\n", message);
80 	RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_write) ==
81 		      ISC_R_SUCCESS);
82 	RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_read) ==
83 		      ISC_R_SUCCESS);
84 	printf("%s got READ lock\n", message);
85 	sleep(1);
86 	printf("%s giving up READ lock\n", message);
87 	RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_read) ==
88 		      ISC_R_SUCCESS);
89 	return ((isc_threadresult_t)0);
90 }
91 
92 int
main(int argc,char * argv[])93 main(int argc, char *argv[]) {
94 	unsigned int nworkers;
95 	unsigned int i;
96 	isc_thread_t workers[100];
97 	char name[100];
98 	void *dupname;
99 
100 	if (argc > 1) {
101 		nworkers = atoi(argv[1]);
102 	} else {
103 		nworkers = 2;
104 	}
105 	if (nworkers > 100) {
106 		nworkers = 100;
107 	}
108 	printf("%u workers\n", nworkers);
109 
110 	isc_rwlock_init(&lock, 5, 10);
111 
112 	for (i = 0; i < nworkers; i++) {
113 		snprintf(name, sizeof(name), "%02u", i);
114 		dupname = strdup(name);
115 		RUNTIME_CHECK(dupname != NULL);
116 		if (i != 0 && i % 3 == 0) {
117 			isc_thread_create(run1, dupname, &workers[i]);
118 		} else {
119 			isc_thread_create(run2, dupname, &workers[i]);
120 		}
121 	}
122 
123 	for (i = 0; i < nworkers; i++) {
124 		isc_thread_join(workers[i], NULL);
125 	}
126 
127 	isc_rwlock_destroy(&lock);
128 
129 	return (0);
130 }
131