1 /* code borrowed from redhat bugzilla report 4979 */
2
3 #define _XOPEN_SOURCE___ 600
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <time.h>
9 #include <sys/time.h>
10 #include <pthread.h>
11
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15
16 #define BUG 1
17 // #define BUG2
18 // #define FILLTEST 1
19 // #define LOCKDUMP 1
20
21 long workercount = 64;
22 long writers = 1;
23 long workerid;
24
25 long writersleep = 100000;
26 long readersleep = 10000;
27 long spincount = 10000000;
28 long spinout = 10000;
29 long procsleep = 100000;
30
31 pthread_rwlock_t mylock;
32 pthread_rwlockattr_t mylock_attr;
33
34
35 void *
lockdump(pthread_rwlock_t * thelock)36 lockdump (pthread_rwlock_t *thelock) {
37 int *mptr = (int *) thelock;
38 int i;
39 for (i=0; i < (sizeof(pthread_rwlock_t) / 4); i++) {
40 printf ("lock %x + %d = %x\n", (void *)thelock, i*4, *(mptr+i));
41 }
42 }
43
44 void *
attrdump(pthread_rwlockattr_t * theattr)45 attrdump (pthread_rwlockattr_t *theattr) {
46 int *mptr = (int *) theattr;
47 int i;
48 for (i=0; i < (sizeof(pthread_rwlockattr_t) / 4); i++) {
49 printf ("attr %x + %d = %x\n", (void *)theattr, i*4, *(mptr+i));
50 }
51 }
52
53 void *
lockclear(pthread_rwlock_t * thelock)54 lockclear (pthread_rwlock_t *thelock) {
55 int *mptr = (int *) thelock;
56 int i;
57 for (i=0; i < (sizeof(pthread_rwlock_t) / 4); i++) {
58 *(mptr+i) = 0;
59 }
60 }
61
62 void *
attrclear(pthread_rwlockattr_t * theattr)63 attrclear (pthread_rwlockattr_t *theattr) {
64 int *mptr = (int *) theattr;
65 int i;
66 for (i=0; i < (sizeof(pthread_rwlockattr_t) / 4); i++) {
67 *(mptr+i) = 0;
68 }
69 }
70
71 void *
lockfill(pthread_rwlock_t * thelock)72 lockfill (pthread_rwlock_t *thelock) {
73 int *mptr = (int *) thelock;
74 int i;
75 for (i=0; i < (sizeof(pthread_rwlock_t) / 4); i++) {
76 *(mptr+i) = 0xffffffff;
77 }
78 }
79
80 void *
attrfill(pthread_rwlockattr_t * theattr)81 attrfill (pthread_rwlockattr_t *theattr) {
82 int *mptr = (int *) theattr;
83 int i;
84 for (i=0; i < (sizeof(pthread_rwlockattr_t) / 4); i++) {
85 *(mptr+i) = 0xffffffff;
86 }
87 }
88
89 void *
reader(long workid,long rwtype)90 reader (long workid, long rwtype)
91 {
92 while (1)
93 {
94 int spn = spincount, spc = spincount;
95
96 printf ("reader %d going for lock\n", workid);
97 pthread_rwlock_rdlock(&mylock);
98 printf ("reader %d obtained the lock\n", workid);
99
100 while (spn != 0) { spn = spc--; }
101 #ifdef LOCKDUMP
102 lockdump (&mylock);
103 #endif
104 pthread_rwlock_unlock(&mylock);
105 printf ("reader %d released the lock at %d\n", workid, spc);
106
107 spn = spinout, spc = spinout;
108 while (spn != 0) { spn = spc--; }
109 #ifdef LOCKDUMP
110 lockdump (&mylock);
111 #endif
112 // printf ("reader %d going yield at %d\n", workid, spc);
113 pthread_yield();
114 usleep(readersleep);
115 }
116 }
117
118
119 void *
writer(long workid,long rwtype)120 writer (long workid, long rwtype)
121 {
122 struct timeval tv;
123 int nc = 5;
124
125 sleep( 1 );
126 while (--nc >= 0)
127 {
128 int spn = spincount, spc = spincount;
129
130 gettimeofday( &tv, NULL );
131 printf ("%04d.%06d writer %d going for lock\n", tv.tv_sec%10000, tv.tv_usec, workid);
132 pthread_rwlock_wrlock(&mylock);
133 #ifdef LOCKDUMP
134 lockdump (&mylock);
135 #endif
136 gettimeofday( &tv, NULL );
137 printf ("%04d.%06d writer %d obtained the lock\n", tv.tv_sec%10000, tv.tv_usec, workid);
138
139 while (spn != 0) { spn = spc--; }
140 pthread_rwlock_unlock(&mylock);
141 printf ("writer %d released the lock at %d\n", workid, spc);
142
143 #ifdef LOCKDUMP
144 lockdump (&mylock);
145 #endif
146 // printf ("writer %d going yield at %d\n", workid, spc);
147 // pthread_yield();
148 usleep( writersleep );
149 // sleep( 4 );
150 }
151
152 pthread_exit( NULL );
153 }
154
155 int
main()156 main () {
157
158 #ifdef FILLTEST
159 printf ("size of lock struct is %d\n", sizeof(pthread_rwlock_t));
160 printf ("address of lock struct is %x\n", &mylock);
161 lockdump (&mylock);
162 attrdump (&mylock_attr);
163 lockfill (&mylock);
164 attrfill (&mylock_attr);
165 lockdump (&mylock);
166 attrdump (&mylock_attr);
167 #endif
168
169 pthread_rwlockattr_init (&mylock_attr);
170 pthread_rwlockattr_setkind_np (&mylock_attr,
171 #if 0
172 PTHREAD_RWLOCK_PREFER_WRITER_NP);
173 #else
174 PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
175 #endif
176 pthread_rwlock_init(&mylock, &mylock_attr);
177
178 #ifdef LOCKDUMP
179 printf ("lock has been initialized\n");
180 lockdump (&mylock);
181 #endif
182
183 pthread_t thrd[workercount];
184
185 pthread_attr_t simple_attr;
186 pthread_attr_init(&simple_attr);
187 pthread_attr_setinheritsched(&simple_attr, PTHREAD_INHERIT_SCHED);
188
189 long res;
190
191 for (workerid = 0; workerid < writers; workerid++) {
192 if (res = pthread_create(&thrd[workerid], &simple_attr,
193 (void *)writer, (void *)workerid)) {
194 printf ("failed to start worker %d, ret %d\n", workerid, res);
195 }
196 }
197 for (workerid = 0; workerid < (workercount - writers); workerid++) {
198 if (res = pthread_create(&thrd[writers+workerid], &simple_attr,
199 (void *)reader, (void *)workerid)) {
200 printf ("failed to start worker %d, ret %d\n", workerid, res);
201 }
202 }
203
204 pthread_join( thrd[0], 0 );
205
206 }
207
208
209 #ifdef __cplusplus
210 }
211 #endif
212