1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6 
7 
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9 
10     PerconaFT is free software: you can redistribute it and/or modify
11     it under the terms of the GNU General Public License, version 2,
12     as published by the Free Software Foundation.
13 
14     PerconaFT is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
21 
22 ----------------------------------------
23 
24     PerconaFT is free software: you can redistribute it and/or modify
25     it under the terms of the GNU Affero General Public License, version 3,
26     as published by the Free Software Foundation.
27 
28     PerconaFT is distributed in the hope that it will be useful,
29     but WITHOUT ANY WARRANTY; without even the implied warranty of
30     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31     GNU Affero General Public License for more details.
32 
33     You should have received a copy of the GNU Affero General Public License
34     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
35 ======= */
36 
37 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38 
39 #include "test.h"
40 
41 // test create and destroy
42 
test_create_destroy(void)43 static void test_create_destroy(void) {
44     struct st_rwlock the_rwlock, *rwlock = &the_rwlock;
45 
46     rwlock_init(toku_uninstrumented, rwlock);
47     rwlock_destroy(rwlock);
48 }
49 
50 // test read lock and unlock with no writers
51 
test_simple_read_lock(int n)52 static void test_simple_read_lock(int n) {
53     struct st_rwlock the_rwlock, *rwlock = &the_rwlock;
54 
55     rwlock_init(toku_uninstrumented, rwlock);
56     assert(rwlock_readers(rwlock) == 0);
57     int i;
58     for (i = 1; i <= n; i++) {
59         rwlock_read_lock(rwlock, 0);
60         assert(rwlock_readers(rwlock) == i);
61         assert(rwlock_users(rwlock) == i);
62     }
63     for (i=n-1; i>=0; i--) {
64         rwlock_read_unlock(rwlock);
65         assert(rwlock_readers(rwlock) == i);
66         assert(rwlock_users(rwlock) == i);
67     }
68     rwlock_destroy(rwlock);
69 }
70 
71 // test write lock and unlock with no readers
72 
test_simple_write_lock(void)73 static void test_simple_write_lock(void) {
74     struct st_rwlock the_rwlock, *rwlock = &the_rwlock;
75 
76     rwlock_init(toku_uninstrumented, rwlock);
77     assert(rwlock_users(rwlock) == 0);
78     rwlock_write_lock(rwlock, 0);
79     assert(rwlock_writers(rwlock) == 1);
80     assert(rwlock_users(rwlock) == 1);
81     rwlock_write_unlock(rwlock);
82     assert(rwlock_users(rwlock) == 0);
83     rwlock_destroy(rwlock);
84 }
85 
86 struct rw_event {
87     int e;
88     struct st_rwlock the_rwlock;
89     toku_mutex_t mutex;
90 };
91 
rw_event_init(struct rw_event * rwe)92 static void rw_event_init(struct rw_event *rwe) {
93     rwe->e = 0;
94     rwlock_init(toku_uninstrumented, &rwe->the_rwlock);
95     toku_mutex_init(toku_uninstrumented, &rwe->mutex, nullptr);
96 }
97 
rw_event_destroy(struct rw_event * rwe)98 static void rw_event_destroy(struct rw_event *rwe) {
99     rwlock_destroy(&rwe->the_rwlock);
100     toku_mutex_destroy(&rwe->mutex);
101 }
102 
103 static void *
test_writer_priority_thread(void * arg)104 test_writer_priority_thread (void *arg) {
105     struct rw_event *CAST_FROM_VOIDP(rwe, arg);
106 
107     toku_mutex_lock(&rwe->mutex);
108     rwlock_write_lock(&rwe->the_rwlock, &rwe->mutex);
109     rwe->e++; assert(rwe->e == 3);
110     toku_mutex_unlock(&rwe->mutex);
111     sleep(1);
112     toku_mutex_lock(&rwe->mutex);
113     rwe->e++; assert(rwe->e == 4);
114     rwlock_write_unlock(&rwe->the_rwlock);
115     toku_mutex_unlock(&rwe->mutex);
116 
117     return arg;
118 }
119 
120 // test writer priority over new readers
121 
122 static void
test_writer_priority(void)123 test_writer_priority (void) {
124     struct rw_event rw_event, *rwe = &rw_event;
125     ZERO_STRUCT(rw_event);
126     int r;
127 
128     rw_event_init(rwe);
129     toku_mutex_lock(&rwe->mutex);
130     rwlock_read_lock(&rwe->the_rwlock, &rwe->mutex);
131     sleep(1);
132     rwe->e++; assert(rwe->e == 1);
133     toku_mutex_unlock(&rwe->mutex);
134 
135     toku_pthread_t tid;
136     r = toku_pthread_create(
137         toku_uninstrumented, &tid, 0, test_writer_priority_thread, rwe);
138     sleep(1);
139     toku_mutex_lock(&rwe->mutex);
140     rwe->e++;
141     assert(rwe->e == 2);
142     toku_mutex_unlock(&rwe->mutex);
143 
144     sleep(1);
145     toku_mutex_lock(&rwe->mutex);
146     rwlock_read_unlock(&rwe->the_rwlock);
147     toku_mutex_unlock(&rwe->mutex);
148     sleep(1);
149     toku_mutex_lock(&rwe->mutex);
150     rwlock_read_lock(&rwe->the_rwlock, &rwe->mutex);
151     rwe->e++; assert(rwe->e == 5);
152     toku_mutex_unlock(&rwe->mutex);
153     sleep(1);
154     toku_mutex_lock(&rwe->mutex);
155     rwlock_read_unlock(&rwe->the_rwlock);
156     toku_mutex_unlock(&rwe->mutex);
157 
158     void *ret;
159     r = toku_pthread_join(tid, &ret); assert(r == 0);
160 
161     rw_event_destroy(rwe);
162 }
163 
164 // test single writer
165 
166 static void *
test_single_writer_thread(void * arg)167 test_single_writer_thread (void *arg) {
168     struct rw_event *CAST_FROM_VOIDP(rwe, arg);
169 
170     toku_mutex_lock(&rwe->mutex);
171     rwlock_write_lock(&rwe->the_rwlock, &rwe->mutex);
172     rwe->e++; assert(rwe->e == 3);
173     assert(rwlock_writers(&rwe->the_rwlock) == 1);
174     rwlock_write_unlock(&rwe->the_rwlock);
175     toku_mutex_unlock(&rwe->mutex);
176 
177     return arg;
178 }
179 
180 static void
test_single_writer(void)181 test_single_writer (void) {
182     struct rw_event rw_event, *rwe = &rw_event;
183     ZERO_STRUCT(rw_event);
184     int r;
185 
186     rw_event_init(rwe);
187     assert(rwlock_writers(&rwe->the_rwlock) == 0);
188     toku_mutex_lock(&rwe->mutex);
189     rwlock_write_lock(&rwe->the_rwlock, &rwe->mutex);
190     assert(rwlock_writers(&rwe->the_rwlock) == 1);
191     sleep(1);
192     rwe->e++; assert(rwe->e == 1);
193     toku_mutex_unlock(&rwe->mutex);
194 
195     toku_pthread_t tid;
196     r = toku_pthread_create(
197         toku_uninstrumented, &tid, 0, test_single_writer_thread, rwe);
198     sleep(1);
199     toku_mutex_lock(&rwe->mutex);
200     rwe->e++;
201     assert(rwe->e == 2);
202     assert(rwlock_writers(&rwe->the_rwlock) == 1);
203     assert(rwlock_users(&rwe->the_rwlock) == 2);
204     rwlock_write_unlock(&rwe->the_rwlock);
205     toku_mutex_unlock(&rwe->mutex);
206 
207     void *ret;
208     r = toku_pthread_join(tid, &ret); assert(r == 0);
209 
210     assert(rwlock_writers(&rwe->the_rwlock) == 0);
211     rw_event_destroy(rwe);
212 }
213 
214 int
test_main(int argc,const char * argv[])215 test_main(int argc, const char *argv[]) {
216     default_parse_args(argc, argv);
217     test_create_destroy();
218     test_simple_read_lock(0);
219     test_simple_read_lock(42);
220     test_simple_write_lock();
221     test_writer_priority();
222     test_single_writer();
223 
224     return 0;
225 }
226