Adjust rx-event test to exercise cancel/fire race
[openafs/adeason.git] / tests / rx / event-t.c
blobc990246540a8ccaf32566243af8e69c473d83f23
1 /* A simple test of the rx event layer */
3 #include <afsconfig.h>
4 #include <afs/param.h>
6 #include <roken.h>
7 #include <pthread.h>
9 #include <tests/tap/basic.h>
11 #include "rx/rx_event.h"
12 #include "rx/rx_clock.h"
14 #define NUMEVENTS 10000
16 /* Mutexes and condvars for the scheduler */
17 static int rescheduled = 0;
18 static pthread_mutex_t eventMutex;
19 static pthread_cond_t eventCond;
21 /* Mutexes and condvars for the event list */
23 static pthread_mutex_t eventListMutex;
24 struct testEvent {
25 struct rxevent *event;
26 int fired;
27 int cancelled;
30 static struct testEvent events[NUMEVENTS];
32 static void
33 reschedule(void)
35 pthread_mutex_lock(&eventMutex);
36 pthread_cond_signal(&eventCond);
37 rescheduled = 1;
38 pthread_mutex_unlock(&eventMutex);
39 return;
42 static void
43 eventSub(struct rxevent *event, void *arg, void *arg1, int arg2)
45 struct testEvent *evrecord = arg;
47 pthread_mutex_lock(&eventListMutex);
48 rxevent_Put(&evrecord->event);
49 evrecord->event = NULL;
50 evrecord->fired = 1;
51 pthread_mutex_unlock(&eventListMutex);
52 return;
55 static void
56 reportSub(struct rxevent *event, void *arg, void *arg1, int arg2)
58 printf("Event fired\n");
61 static void *
62 eventHandler(void *dummy) {
63 struct timespec nextEvent;
64 struct clock cv;
65 struct clock next;
67 pthread_mutex_lock(&eventMutex);
68 while (1) {
69 pthread_mutex_unlock(&eventMutex);
71 next.sec = 30;
72 next.usec = 0;
73 clock_GetTime(&cv);
74 rxevent_RaiseEvents(&next);
76 pthread_mutex_lock(&eventMutex);
78 /* If we were rescheduled whilst running the event queue,
79 * process the queue again */
80 if (rescheduled) {
81 rescheduled = 0;
82 continue;
85 clock_Add(&cv, &next);
86 nextEvent.tv_sec = cv.sec;
87 nextEvent.tv_nsec = cv.usec * 1000;
88 pthread_cond_timedwait(&eventCond, &eventMutex, &nextEvent);
90 pthread_mutex_unlock(&eventMutex);
92 return NULL;
95 int
96 main(void)
98 int when, counter, fail, fired, cancelled;
99 struct clock now, eventTime;
100 struct rxevent *event;
101 pthread_t handler;
103 plan(8);
105 pthread_mutex_init(&eventMutex, NULL);
106 pthread_cond_init(&eventCond, NULL);
108 memset(events, 0, sizeof(events));
109 pthread_mutex_init(&eventListMutex, NULL);
111 /* Start up the event system */
112 rxevent_Init(20, reschedule);
113 ok(1, "Started event subsystem");
115 clock_GetTime(&now);
116 /* Test for a problem when there is only a single event in the tree */
117 event = rxevent_Post(&now, &now, reportSub, NULL, NULL, 0);
118 ok(event != NULL, "Created a single event");
119 rxevent_Cancel(&event);
120 ok(1, "Cancelled a single event");
121 rxevent_RaiseEvents(&now);
122 ok(1, "RaiseEvents happened without error");
124 ok(pthread_create(&handler, NULL, eventHandler, NULL) == 0,
125 "Created handler thread");
127 /* Add 1000 random events to fire over the next 3 seconds, but front-loaded
128 * a bit so that we can exercise the cancel/fire race path. */
130 for (counter = 0; counter < NUMEVENTS; counter++) {
131 when = random() % 4000;
132 /* Put 1/4 of events "right away" so we cancel them as they fire */
133 if (when >= 3000)
134 when = random() % 5;
135 clock_GetTime(&now);
136 eventTime = now;
137 clock_Addmsec(&eventTime, when);
138 pthread_mutex_lock(&eventListMutex);
139 events[counter].event
140 = rxevent_Post(&eventTime, &now, eventSub, &events[counter], NULL, 0);
142 /* A 10% chance that we will schedule another event at the same time */
143 if (counter!=999 && random() % 10 == 0) {
144 counter++;
145 events[counter].event
146 = rxevent_Post(&eventTime, &now, eventSub, &events[counter],
147 NULL, 0);
150 /* A 25% chance that we will cancel a random event */
151 if (random() % 4 == 0) {
152 int victim = random() % counter;
154 if (events[victim].event != NULL) {
155 rxevent_Cancel(&events[victim].event);
156 events[victim].cancelled = 1;
159 pthread_mutex_unlock(&eventListMutex);
162 ok(1, "Added %d events", NUMEVENTS);
164 sleep(3);
166 fired = 0;
167 cancelled = 0;
168 fail = 0;
169 for (counter = 0; counter < NUMEVENTS; counter++) {
170 if (events[counter].fired)
171 fired++;
172 if (events[counter].cancelled)
173 cancelled++;
174 if (events[counter].cancelled && events[counter].fired)
175 fail = 1;
177 ok(!fail, "Didn't fire any cancelled events");
178 ok(fired+cancelled == NUMEVENTS,
179 "Number of fired and cancelled events sum to correct total");
181 return 0;