1275970Scy/* 2275970Scy * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 3275970Scy * 4275970Scy * Permission to use, copy, modify, and/or distribute this software for any 5275970Scy * purpose with or without fee is hereby granted, provided that the above 6275970Scy * copyright notice and this permission notice appear in all copies. 7275970Scy * 8275970Scy * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9275970Scy * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10275970Scy * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11275970Scy * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12275970Scy * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13275970Scy * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14275970Scy * PERFORMANCE OF THIS SOFTWARE. 15275970Scy */ 16275970Scy 17275970Scy/* $Id$ */ 18275970Scy 19275970Scy/*! \file */ 20275970Scy 21275970Scy#include <config.h> 22275970Scy 23275970Scy#include <atf-c.h> 24275970Scy 25275970Scy#include <unistd.h> 26275970Scy 27275970Scy#include <isc/task.h> 28275970Scy#include <isc/util.h> 29275970Scy 30275970Scy#include "../task_p.h" 31275970Scy#include "isctest.h" 32275970Scy 33275970Scy/* 34275970Scy * Helper functions 35275970Scy */ 36275970Scy 37275970Scy/* task event handler, sets a boolean to true */ 38275970Scyint counter = 0; 39275970Scyisc_mutex_t set_lock; 40275970Scy 41275970Scystatic void 42275970Scyset(isc_task_t *task, isc_event_t *event) { 43275970Scy int *value = (int *) event->ev_arg; 44275970Scy 45275970Scy UNUSED(task); 46275970Scy 47275970Scy isc_event_free(&event); 48275970Scy LOCK(&set_lock); 49275970Scy *value = counter++; 50275970Scy UNLOCK(&set_lock); 51275970Scy} 52275970Scy 53275970Scystatic void 54275970Scyset_and_drop(isc_task_t *task, isc_event_t *event) { 55275970Scy int *value = (int *) event->ev_arg; 56275970Scy 57275970Scy UNUSED(task); 58275970Scy 59275970Scy isc_event_free(&event); 60275970Scy LOCK(&set_lock); 61275970Scy *value = (int) isc_taskmgr_mode(taskmgr); 62275970Scy counter++; 63275970Scy UNLOCK(&set_lock); 64275970Scy isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_normal); 65275970Scy} 66275970Scy 67275970Scy/* 68275970Scy * Individual unit tests 69275970Scy */ 70275970Scy 71275970Scy/* Create a task */ 72275970ScyATF_TC(create_task); 73275970ScyATF_TC_HEAD(create_task, tc) { 74275970Scy atf_tc_set_md_var(tc, "descr", "create and destroy a task"); 75275970Scy} 76275970ScyATF_TC_BODY(create_task, tc) { 77275970Scy isc_result_t result; 78275970Scy isc_task_t *task = NULL; 79275970Scy 80275970Scy UNUSED(tc); 81275970Scy 82275970Scy result = isc_test_begin(NULL, ISC_TRUE); 83275970Scy ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 84275970Scy 85275970Scy result = isc_task_create(taskmgr, 0, &task); 86275970Scy ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 87275970Scy 88275970Scy isc_task_destroy(&task); 89275970Scy ATF_REQUIRE_EQ(task, NULL); 90275970Scy 91275970Scy isc_test_end(); 92275970Scy} 93275970Scy 94275970Scy/* Process events */ 95275970ScyATF_TC(all_events); 96275970ScyATF_TC_HEAD(all_events, tc) { 97275970Scy atf_tc_set_md_var(tc, "descr", "process task events"); 98275970Scy} 99275970ScyATF_TC_BODY(all_events, tc) { 100275970Scy isc_result_t result; 101275970Scy isc_task_t *task = NULL; 102275970Scy isc_event_t *event; 103275970Scy int a = 0, b = 0; 104275970Scy int i = 0; 105275970Scy 106275970Scy UNUSED(tc); 107275970Scy 108275970Scy counter = 1; 109275970Scy 110275970Scy result = isc_mutex_init(&set_lock); 111275970Scy ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 112275970Scy 113275970Scy result = isc_test_begin(NULL, ISC_TRUE); 114275970Scy ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 115275970Scy 116275970Scy result = isc_task_create(taskmgr, 0, &task); 117275970Scy ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 118275970Scy 119275970Scy /* First event */ 120275970Scy event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST, 121275970Scy set, &a, sizeof (isc_event_t)); 122275970Scy ATF_REQUIRE(event != NULL); 123275970Scy 124275970Scy ATF_CHECK_EQ(a, 0); 125275970Scy isc_task_send(task, &event); 126275970Scy 127275970Scy event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST, 128275970Scy set, &b, sizeof (isc_event_t)); 129275970Scy ATF_REQUIRE(event != NULL); 130275970Scy 131275970Scy ATF_CHECK_EQ(b, 0); 132275970Scy isc_task_send(task, &event); 133275970Scy 134275970Scy while ((a == 0 || b == 0) && i++ < 5000) { 135275970Scy#ifndef ISC_PLATFORM_USETHREADS 136275970Scy while (isc__taskmgr_ready(taskmgr)) 137275970Scy isc__taskmgr_dispatch(taskmgr); 138275970Scy#endif 139275970Scy isc_test_nap(1000); 140275970Scy } 141275970Scy 142275970Scy ATF_CHECK(a != 0); 143275970Scy ATF_CHECK(b != 0); 144275970Scy 145275970Scy isc_task_destroy(&task); 146275970Scy ATF_REQUIRE_EQ(task, NULL); 147275970Scy 148275970Scy isc_test_end(); 149275970Scy} 150275970Scy 151275970Scy/* Privileged events */ 152275970ScyATF_TC(privileged_events); 153275970ScyATF_TC_HEAD(privileged_events, tc) { 154275970Scy atf_tc_set_md_var(tc, "descr", "process privileged events"); 155275970Scy} 156275970ScyATF_TC_BODY(privileged_events, tc) { 157275970Scy isc_result_t result; 158275970Scy isc_task_t *task1 = NULL, *task2 = NULL; 159275970Scy isc_event_t *event; 160275970Scy int a = 0, b = 0, c = 0, d = 0, e = 0; 161275970Scy int i = 0; 162275970Scy 163275970Scy UNUSED(tc); 164275970Scy 165275970Scy counter = 1; 166275970Scy result = isc_mutex_init(&set_lock); 167275970Scy ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 168275970Scy 169275970Scy result = isc_test_begin(NULL, ISC_TRUE); 170275970Scy ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 171275970Scy 172275970Scy#ifdef ISC_PLATFORM_USETHREADS 173275970Scy /* 174275970Scy * Pause the task manager so we can fill up the work queue 175275970Scy * without things happening while we do it. 176275970Scy */ 177275970Scy isc__taskmgr_pause(taskmgr); 178275970Scy#endif 179275970Scy 180275970Scy result = isc_task_create(taskmgr, 0, &task1); 181275970Scy ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 182275970Scy isc_task_setname(task1, "privileged", NULL); 183275970Scy ATF_CHECK(!isc_task_privilege(task1)); 184275970Scy isc_task_setprivilege(task1, ISC_TRUE); 185275970Scy ATF_CHECK(isc_task_privilege(task1)); 186275970Scy 187275970Scy result = isc_task_create(taskmgr, 0, &task2); 188275970Scy ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 189275970Scy isc_task_setname(task2, "normal", NULL); 190275970Scy ATF_CHECK(!isc_task_privilege(task2)); 191275970Scy 192275970Scy /* First event: privileged */ 193275970Scy event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, 194275970Scy set, &a, sizeof (isc_event_t)); 195275970Scy ATF_REQUIRE(event != NULL); 196275970Scy 197275970Scy ATF_CHECK_EQ(a, 0); 198275970Scy isc_task_send(task1, &event); 199275970Scy 200275970Scy /* Second event: not privileged */ 201275970Scy event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, 202275970Scy set, &b, sizeof (isc_event_t)); 203275970Scy ATF_REQUIRE(event != NULL); 204275970Scy 205275970Scy ATF_CHECK_EQ(b, 0); 206275970Scy isc_task_send(task2, &event); 207275970Scy 208275970Scy /* Third event: privileged */ 209275970Scy event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, 210275970Scy set, &c, sizeof (isc_event_t)); 211275970Scy ATF_REQUIRE(event != NULL); 212275970Scy 213275970Scy ATF_CHECK_EQ(c, 0); 214275970Scy isc_task_send(task1, &event); 215275970Scy 216275970Scy /* Fourth event: privileged */ 217275970Scy event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, 218275970Scy set, &d, sizeof (isc_event_t)); 219275970Scy ATF_REQUIRE(event != NULL); 220275970Scy 221275970Scy ATF_CHECK_EQ(d, 0); 222275970Scy isc_task_send(task1, &event); 223275970Scy 224275970Scy /* Fifth event: not privileged */ 225275970Scy event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, 226275970Scy set, &e, sizeof (isc_event_t)); 227275970Scy ATF_REQUIRE(event != NULL); 228275970Scy 229275970Scy ATF_CHECK_EQ(e, 0); 230275970Scy isc_task_send(task2, &event); 231275970Scy 232275970Scy ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal); 233275970Scy isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged); 234275970Scy ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_privileged); 235275970Scy 236275970Scy#ifdef ISC_PLATFORM_USETHREADS 237275970Scy isc__taskmgr_resume(taskmgr); 238275970Scy#endif 239275970Scy 240275970Scy /* We're waiting for *all* variables to be set */ 241275970Scy while ((a == 0 || b == 0 || c == 0 || d == 0 || e == 0) && i++ < 5000) { 242275970Scy#ifndef ISC_PLATFORM_USETHREADS 243275970Scy while (isc__taskmgr_ready(taskmgr)) 244275970Scy isc__taskmgr_dispatch(taskmgr); 245275970Scy#endif 246275970Scy isc_test_nap(1000); 247275970Scy } 248275970Scy 249275970Scy /* 250275970Scy * We can't guarantee what order the events fire, but 251275970Scy * we do know the privileged tasks that set a, c, and d 252275970Scy * would have fired first. 253275970Scy */ 254275970Scy ATF_CHECK(a <= 3); 255275970Scy ATF_CHECK(c <= 3); 256275970Scy ATF_CHECK(d <= 3); 257275970Scy 258275970Scy /* ...and the non-privileged tasks that set b and e, last */ 259275970Scy ATF_CHECK(b >= 4); 260275970Scy ATF_CHECK(e >= 4); 261275970Scy 262275970Scy ATF_CHECK_EQ(counter, 6); 263275970Scy 264275970Scy isc_task_setprivilege(task1, ISC_FALSE); 265275970Scy ATF_CHECK(!isc_task_privilege(task1)); 266275970Scy 267275970Scy ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal); 268275970Scy 269275970Scy isc_task_destroy(&task1); 270275970Scy ATF_REQUIRE_EQ(task1, NULL); 271275970Scy isc_task_destroy(&task2); 272275970Scy ATF_REQUIRE_EQ(task2, NULL); 273275970Scy 274275970Scy isc_test_end(); 275275970Scy} 276275970Scy 277275970Scy/* 278275970Scy * Edge case: this tests that the task manager behaves as expected when 279275970Scy * we explicitly set it into normal mode *while* running privileged. 280275970Scy */ 281275970ScyATF_TC(privilege_drop); 282275970ScyATF_TC_HEAD(privilege_drop, tc) { 283275970Scy atf_tc_set_md_var(tc, "descr", "process privileged events"); 284275970Scy} 285275970ScyATF_TC_BODY(privilege_drop, tc) { 286275970Scy isc_result_t result; 287275970Scy isc_task_t *task1 = NULL, *task2 = NULL; 288275970Scy isc_event_t *event; 289275970Scy int a = -1, b = -1, c = -1, d = -1, e = -1; /* non valid states */ 290275970Scy int i = 0; 291275970Scy 292275970Scy UNUSED(tc); 293275970Scy 294275970Scy counter = 1; 295275970Scy result = isc_mutex_init(&set_lock); 296275970Scy ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 297275970Scy 298275970Scy result = isc_test_begin(NULL, ISC_TRUE); 299275970Scy ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 300275970Scy 301275970Scy#ifdef ISC_PLATFORM_USETHREADS 302275970Scy /* 303275970Scy * Pause the task manager so we can fill up the work queue 304275970Scy * without things happening while we do it. 305275970Scy */ 306275970Scy isc__taskmgr_pause(taskmgr); 307275970Scy#endif 308275970Scy 309275970Scy result = isc_task_create(taskmgr, 0, &task1); 310275970Scy ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 311275970Scy isc_task_setname(task1, "privileged", NULL); 312275970Scy ATF_CHECK(!isc_task_privilege(task1)); 313275970Scy isc_task_setprivilege(task1, ISC_TRUE); 314275970Scy ATF_CHECK(isc_task_privilege(task1)); 315275970Scy 316275970Scy result = isc_task_create(taskmgr, 0, &task2); 317275970Scy ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 318275970Scy isc_task_setname(task2, "normal", NULL); 319275970Scy ATF_CHECK(!isc_task_privilege(task2)); 320275970Scy 321275970Scy /* First event: privileged */ 322275970Scy event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, 323275970Scy set_and_drop, &a, sizeof (isc_event_t)); 324275970Scy ATF_REQUIRE(event != NULL); 325275970Scy 326275970Scy ATF_CHECK_EQ(a, -1); 327275970Scy isc_task_send(task1, &event); 328275970Scy 329275970Scy /* Second event: not privileged */ 330275970Scy event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, 331275970Scy set_and_drop, &b, sizeof (isc_event_t)); 332275970Scy ATF_REQUIRE(event != NULL); 333275970Scy 334275970Scy ATF_CHECK_EQ(b, -1); 335275970Scy isc_task_send(task2, &event); 336275970Scy 337275970Scy /* Third event: privileged */ 338275970Scy event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, 339275970Scy set_and_drop, &c, sizeof (isc_event_t)); 340275970Scy ATF_REQUIRE(event != NULL); 341275970Scy 342275970Scy ATF_CHECK_EQ(c, -1); 343275970Scy isc_task_send(task1, &event); 344275970Scy 345275970Scy /* Fourth event: privileged */ 346275970Scy event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, 347275970Scy set_and_drop, &d, sizeof (isc_event_t)); 348275970Scy ATF_REQUIRE(event != NULL); 349275970Scy 350275970Scy ATF_CHECK_EQ(d, -1); 351275970Scy isc_task_send(task1, &event); 352275970Scy 353275970Scy /* Fifth event: not privileged */ 354275970Scy event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, 355275970Scy set_and_drop, &e, sizeof (isc_event_t)); 356275970Scy ATF_REQUIRE(event != NULL); 357275970Scy 358275970Scy ATF_CHECK_EQ(e, -1); 359275970Scy isc_task_send(task2, &event); 360275970Scy 361275970Scy ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal); 362275970Scy isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged); 363275970Scy ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_privileged); 364275970Scy 365275970Scy#ifdef ISC_PLATFORM_USETHREADS 366275970Scy isc__taskmgr_resume(taskmgr); 367275970Scy#endif 368275970Scy 369275970Scy /* We're waiting for all variables to be set. */ 370275970Scy while ((a == -1 || b == -1 || c == -1 || d == -1 || e == -1) && 371275970Scy i++ < 5000) { 372275970Scy#ifndef ISC_PLATFORM_USETHREADS 373275970Scy while (isc__taskmgr_ready(taskmgr)) 374275970Scy isc__taskmgr_dispatch(taskmgr); 375275970Scy#endif 376275970Scy isc_test_nap(1000); 377275970Scy } 378275970Scy 379275970Scy /* 380275970Scy * We can't guarantee what order the events fire, but 381275970Scy * we do know *exactly one* of the privileged tasks will 382275970Scy * have run in privileged mode... 383275970Scy */ 384275970Scy ATF_CHECK(a == isc_taskmgrmode_privileged || 385275970Scy c == isc_taskmgrmode_privileged || 386275970Scy d == isc_taskmgrmode_privileged); 387275970Scy ATF_CHECK(a + c + d == isc_taskmgrmode_privileged); 388275970Scy 389275970Scy /* ...and neither of the non-privileged tasks did... */ 390275970Scy ATF_CHECK(b == isc_taskmgrmode_normal || e == isc_taskmgrmode_normal); 391275970Scy 392275970Scy /* ...but all five of them did run. */ 393275970Scy ATF_CHECK_EQ(counter, 6); 394275970Scy 395275970Scy ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal); 396275970Scy 397275970Scy isc_task_destroy(&task1); 398275970Scy ATF_REQUIRE_EQ(task1, NULL); 399275970Scy isc_task_destroy(&task2); 400275970Scy ATF_REQUIRE_EQ(task2, NULL); 401275970Scy 402275970Scy isc_test_end(); 403275970Scy} 404275970Scy 405275970Scy/* 406275970Scy * Main 407275970Scy */ 408275970ScyATF_TP_ADD_TCS(tp) { 409275970Scy ATF_TP_ADD_TC(tp, create_task); 410275970Scy ATF_TP_ADD_TC(tp, all_events); 411275970Scy ATF_TP_ADD_TC(tp, privileged_events); 412275970Scy ATF_TP_ADD_TC(tp, privilege_drop); 413275970Scy 414275970Scy return (atf_no_error()); 415275970Scy} 416275970Scy 417