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