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