1 /* $NetBSD: shutdown_test.c,v 1.7 2014/12/10 04:37:53 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2007, 2011, 2013 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1998-2001 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id: shutdown_test.c,v 1.25 2011/08/28 23:46:41 tbox Exp */ 21 22 #include <config.h> 23 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include <isc/app.h> 28 #include <isc/mem.h> 29 #include <isc/print.h> 30 #include <isc/task.h> 31 #include <isc/time.h> 32 #include <isc/timer.h> 33 #include <isc/util.h> 34 35 typedef struct { 36 isc_mem_t * mctx; 37 isc_task_t * task; 38 isc_timer_t * timer; 39 unsigned int ticks; 40 char name[16]; 41 isc_boolean_t exiting; 42 isc_task_t * peer; 43 } t_info; 44 45 #define MAX_TASKS 3 46 #define T2_SHUTDOWNOK (ISC_EVENTCLASS(1024) + 0) 47 #define T2_SHUTDOWNDONE (ISC_EVENTCLASS(1024) + 1) 48 #define FOO_EVENT (ISC_EVENTCLASS(1024) + 2) 49 50 static t_info tasks[MAX_TASKS]; 51 static unsigned int task_count; 52 static isc_taskmgr_t * task_manager; 53 static isc_timermgr_t * timer_manager; 54 55 static void 56 t1_shutdown(isc_task_t *task, isc_event_t *event) { 57 t_info *info = event->ev_arg; 58 59 printf("task %s (%p) t1_shutdown\n", info->name, task); 60 isc_task_detach(&info->task); 61 isc_event_free(&event); 62 } 63 64 static void 65 t2_shutdown(isc_task_t *task, isc_event_t *event) { 66 t_info *info = event->ev_arg; 67 68 printf("task %s (%p) t2_shutdown\n", info->name, task); 69 info->exiting = ISC_TRUE; 70 isc_event_free(&event); 71 } 72 73 static void 74 shutdown_action(isc_task_t *task, isc_event_t *event) { 75 t_info *info = event->ev_arg; 76 isc_event_t *nevent; 77 78 INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN); 79 80 printf("task %s (%p) shutdown\n", info->name, task); 81 if (strcmp(info->name, "0") == 0) { 82 isc_timer_detach(&info->timer); 83 nevent = isc_event_allocate(info->mctx, info, T2_SHUTDOWNOK, 84 t2_shutdown, &tasks[1], 85 sizeof(*event)); 86 RUNTIME_CHECK(nevent != NULL); 87 info->exiting = ISC_TRUE; 88 isc_task_sendanddetach(&info->peer, &nevent); 89 } 90 isc_event_free(&event); 91 } 92 93 static void 94 foo_event(isc_task_t *task, isc_event_t *event) { 95 printf("task(%p) foo\n", task); 96 isc_event_free(&event); 97 } 98 99 static void 100 tick(isc_task_t *task, isc_event_t *event) { 101 t_info *info = event->ev_arg; 102 isc_event_t *nevent; 103 104 INSIST(event->ev_type == ISC_TIMEREVENT_TICK); 105 106 printf("task %s (%p) tick\n", info->name, task); 107 108 info->ticks++; 109 if (strcmp(info->name, "1") == 0) { 110 if (info->ticks == 10) { 111 RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS); 112 } else if (info->ticks >= 15 && info->exiting) { 113 isc_timer_detach(&info->timer); 114 isc_task_detach(&info->task); 115 nevent = isc_event_allocate(info->mctx, info, 116 T2_SHUTDOWNDONE, 117 t1_shutdown, &tasks[0], 118 sizeof(*event)); 119 RUNTIME_CHECK(nevent != NULL); 120 isc_task_send(info->peer, &nevent); 121 isc_task_detach(&info->peer); 122 } 123 } else if (strcmp(info->name, "foo") == 0) { 124 isc_timer_detach(&info->timer); 125 nevent = isc_event_allocate(info->mctx, info, 126 FOO_EVENT, 127 foo_event, task, 128 sizeof(*event)); 129 RUNTIME_CHECK(nevent != NULL); 130 isc_task_sendanddetach(&task, &nevent); 131 } 132 133 isc_event_free(&event); 134 } 135 136 static t_info * 137 new_task(isc_mem_t *mctx, const char *name) { 138 t_info *ti; 139 isc_time_t expires; 140 isc_interval_t interval; 141 142 RUNTIME_CHECK(task_count < MAX_TASKS); 143 ti = &tasks[task_count]; 144 ti->mctx = mctx; 145 ti->task = NULL; 146 ti->timer = NULL; 147 ti->ticks = 0; 148 if (name != NULL) { 149 INSIST(strlen(name) < sizeof(ti->name)); 150 strcpy(ti->name, name); 151 } else 152 sprintf(ti->name, "%d", task_count); 153 RUNTIME_CHECK(isc_task_create(task_manager, 0, &ti->task) == 154 ISC_R_SUCCESS); 155 RUNTIME_CHECK(isc_task_onshutdown(ti->task, shutdown_action, ti) == 156 ISC_R_SUCCESS); 157 158 isc_time_settoepoch(&expires); 159 isc_interval_set(&interval, 1, 0); 160 RUNTIME_CHECK(isc_timer_create(timer_manager, isc_timertype_ticker, 161 &expires, &interval, ti->task, 162 tick, ti, &ti->timer) == 163 ISC_R_SUCCESS); 164 165 task_count++; 166 167 return (ti); 168 } 169 170 int 171 main(int argc, char *argv[]) { 172 unsigned int workers; 173 t_info *t1, *t2; 174 isc_task_t *task; 175 isc_mem_t *mctx, *mctx2; 176 177 RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS); 178 179 if (argc > 1) { 180 workers = atoi(argv[1]); 181 if (workers < 1) 182 workers = 1; 183 if (workers > 8192) 184 workers = 8192; 185 } else 186 workers = 2; 187 printf("%d workers\n", workers); 188 189 mctx = NULL; 190 RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); 191 mctx2 = NULL; 192 RUNTIME_CHECK(isc_mem_create(0, 0, &mctx2) == ISC_R_SUCCESS); 193 RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, &task_manager) == 194 ISC_R_SUCCESS); 195 RUNTIME_CHECK(isc_timermgr_create(mctx, &timer_manager) == 196 ISC_R_SUCCESS); 197 198 t1 = new_task(mctx, NULL); 199 t2 = new_task(mctx2, NULL); 200 isc_task_attach(t2->task, &t1->peer); 201 isc_task_attach(t1->task, &t2->peer); 202 203 /* 204 * Test run-triggered shutdown. 205 */ 206 (void)new_task(mctx2, "foo"); 207 208 /* 209 * Test implicit shutdown. 210 */ 211 task = NULL; 212 RUNTIME_CHECK(isc_task_create(task_manager, 0, &task) == 213 ISC_R_SUCCESS); 214 isc_task_detach(&task); 215 216 /* 217 * Test anti-zombie code. 218 */ 219 RUNTIME_CHECK(isc_task_create(task_manager, 0, &task) == 220 ISC_R_SUCCESS); 221 isc_task_detach(&task); 222 223 RUNTIME_CHECK(isc_app_run() == ISC_R_SUCCESS); 224 225 isc_taskmgr_destroy(&task_manager); 226 isc_timermgr_destroy(&timer_manager); 227 228 printf("Statistics for mctx:\n"); 229 isc_mem_stats(mctx, stdout); 230 isc_mem_destroy(&mctx); 231 printf("Statistics for mctx2:\n"); 232 isc_mem_stats(mctx2, stdout); 233 isc_mem_destroy(&mctx2); 234 235 isc_app_finish(); 236 237 return (0); 238 } 239