1290001Sglebius/* 2290001Sglebius * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 3290001Sglebius * 4290001Sglebius * Permission to use, copy, modify, and/or distribute this software for any 5290001Sglebius * purpose with or without fee is hereby granted, provided that the above 6290001Sglebius * copyright notice and this permission notice appear in all copies. 7290001Sglebius * 8290001Sglebius * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9290001Sglebius * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10290001Sglebius * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11290001Sglebius * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12290001Sglebius * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13290001Sglebius * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14290001Sglebius * PERFORMANCE OF THIS SOFTWARE. 15290001Sglebius */ 16290001Sglebius 17290001Sglebius/* $Id$ */ 18290001Sglebius 19290001Sglebius/*! \file */ 20290001Sglebius 21290001Sglebius#include <config.h> 22290001Sglebius 23290001Sglebius#include <atf-c.h> 24290001Sglebius 25290001Sglebius#include <unistd.h> 26290001Sglebius 27290001Sglebius#include <isc/task.h> 28290001Sglebius#include <isc/util.h> 29290001Sglebius 30290001Sglebius#include "../task_p.h" 31290001Sglebius#include "isctest.h" 32290001Sglebius 33290001Sglebius/* 34290001Sglebius * Helper functions 35290001Sglebius */ 36290001Sglebius 37290001Sglebius/* task event handler, sets a boolean to true */ 38290001Sglebiusint counter = 0; 39290001Sglebiusisc_mutex_t set_lock; 40290001Sglebius 41290001Sglebiusstatic void 42290001Sglebiusset(isc_task_t *task, isc_event_t *event) { 43290001Sglebius int *value = (int *) event->ev_arg; 44290001Sglebius 45290001Sglebius UNUSED(task); 46290001Sglebius 47290001Sglebius isc_event_free(&event); 48290001Sglebius LOCK(&set_lock); 49290001Sglebius *value = counter++; 50290001Sglebius UNLOCK(&set_lock); 51290001Sglebius} 52290001Sglebius 53290001Sglebiusstatic void 54290001Sglebiusset_and_drop(isc_task_t *task, isc_event_t *event) { 55290001Sglebius int *value = (int *) event->ev_arg; 56290001Sglebius 57290001Sglebius UNUSED(task); 58290001Sglebius 59290001Sglebius isc_event_free(&event); 60290001Sglebius LOCK(&set_lock); 61290001Sglebius *value = (int) isc_taskmgr_mode(taskmgr); 62290001Sglebius counter++; 63290001Sglebius UNLOCK(&set_lock); 64290001Sglebius isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_normal); 65290001Sglebius} 66290001Sglebius 67290001Sglebius/* 68290001Sglebius * Individual unit tests 69290001Sglebius */ 70290001Sglebius 71290001Sglebius/* Create a task */ 72290001SglebiusATF_TC(create_task); 73290001SglebiusATF_TC_HEAD(create_task, tc) { 74290001Sglebius atf_tc_set_md_var(tc, "descr", "create and destroy a task"); 75290001Sglebius} 76290001SglebiusATF_TC_BODY(create_task, tc) { 77290001Sglebius isc_result_t result; 78290001Sglebius isc_task_t *task = NULL; 79290001Sglebius 80290001Sglebius UNUSED(tc); 81290001Sglebius 82290001Sglebius result = isc_test_begin(NULL, ISC_TRUE); 83290001Sglebius ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 84290001Sglebius 85290001Sglebius result = isc_task_create(taskmgr, 0, &task); 86290001Sglebius ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 87290001Sglebius 88290001Sglebius isc_task_destroy(&task); 89290001Sglebius ATF_REQUIRE_EQ(task, NULL); 90290001Sglebius 91290001Sglebius isc_test_end(); 92290001Sglebius} 93290001Sglebius 94290001Sglebius/* Process events */ 95290001SglebiusATF_TC(all_events); 96290001SglebiusATF_TC_HEAD(all_events, tc) { 97290001Sglebius atf_tc_set_md_var(tc, "descr", "process task events"); 98290001Sglebius} 99290001SglebiusATF_TC_BODY(all_events, tc) { 100290001Sglebius isc_result_t result; 101290001Sglebius isc_task_t *task = NULL; 102290001Sglebius isc_event_t *event; 103290001Sglebius int a = 0, b = 0; 104290001Sglebius int i = 0; 105290001Sglebius 106290001Sglebius UNUSED(tc); 107290001Sglebius 108290001Sglebius counter = 1; 109290001Sglebius 110290001Sglebius result = isc_mutex_init(&set_lock); 111290001Sglebius ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 112290001Sglebius 113290001Sglebius result = isc_test_begin(NULL, ISC_TRUE); 114290001Sglebius ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 115290001Sglebius 116290001Sglebius result = isc_task_create(taskmgr, 0, &task); 117290001Sglebius ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 118290001Sglebius 119290001Sglebius /* First event */ 120290001Sglebius event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST, 121290001Sglebius set, &a, sizeof (isc_event_t)); 122290001Sglebius ATF_REQUIRE(event != NULL); 123290001Sglebius 124290001Sglebius ATF_CHECK_EQ(a, 0); 125290001Sglebius isc_task_send(task, &event); 126290001Sglebius 127290001Sglebius event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST, 128290001Sglebius set, &b, sizeof (isc_event_t)); 129290001Sglebius ATF_REQUIRE(event != NULL); 130290001Sglebius 131290001Sglebius ATF_CHECK_EQ(b, 0); 132290001Sglebius isc_task_send(task, &event); 133290001Sglebius 134290001Sglebius while ((a == 0 || b == 0) && i++ < 5000) { 135290001Sglebius#ifndef ISC_PLATFORM_USETHREADS 136290001Sglebius while (isc__taskmgr_ready(taskmgr)) 137290001Sglebius isc__taskmgr_dispatch(taskmgr); 138290001Sglebius#endif 139290001Sglebius isc_test_nap(1000); 140290001Sglebius } 141290001Sglebius 142290001Sglebius ATF_CHECK(a != 0); 143290001Sglebius ATF_CHECK(b != 0); 144290001Sglebius 145290001Sglebius isc_task_destroy(&task); 146290001Sglebius ATF_REQUIRE_EQ(task, NULL); 147290001Sglebius 148290001Sglebius isc_test_end(); 149290001Sglebius} 150290001Sglebius 151290001Sglebius/* Privileged events */ 152290001SglebiusATF_TC(privileged_events); 153290001SglebiusATF_TC_HEAD(privileged_events, tc) { 154290001Sglebius atf_tc_set_md_var(tc, "descr", "process privileged events"); 155290001Sglebius} 156290001SglebiusATF_TC_BODY(privileged_events, tc) { 157290001Sglebius isc_result_t result; 158290001Sglebius isc_task_t *task1 = NULL, *task2 = NULL; 159290001Sglebius isc_event_t *event; 160290001Sglebius int a = 0, b = 0, c = 0, d = 0, e = 0; 161290001Sglebius int i = 0; 162290001Sglebius 163290001Sglebius UNUSED(tc); 164290001Sglebius 165290001Sglebius counter = 1; 166290001Sglebius result = isc_mutex_init(&set_lock); 167290001Sglebius ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 168290001Sglebius 169290001Sglebius result = isc_test_begin(NULL, ISC_TRUE); 170290001Sglebius ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 171290001Sglebius 172290001Sglebius#ifdef ISC_PLATFORM_USETHREADS 173290001Sglebius /* 174290001Sglebius * Pause the task manager so we can fill up the work queue 175290001Sglebius * without things happening while we do it. 176290001Sglebius */ 177290001Sglebius isc__taskmgr_pause(taskmgr); 178290001Sglebius#endif 179290001Sglebius 180290001Sglebius result = isc_task_create(taskmgr, 0, &task1); 181290001Sglebius ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 182290001Sglebius isc_task_setname(task1, "privileged", NULL); 183290001Sglebius ATF_CHECK(!isc_task_privilege(task1)); 184290001Sglebius isc_task_setprivilege(task1, ISC_TRUE); 185290001Sglebius ATF_CHECK(isc_task_privilege(task1)); 186290001Sglebius 187290001Sglebius result = isc_task_create(taskmgr, 0, &task2); 188290001Sglebius ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 189290001Sglebius isc_task_setname(task2, "normal", NULL); 190290001Sglebius ATF_CHECK(!isc_task_privilege(task2)); 191290001Sglebius 192290001Sglebius /* First event: privileged */ 193290001Sglebius event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, 194290001Sglebius set, &a, sizeof (isc_event_t)); 195290001Sglebius ATF_REQUIRE(event != NULL); 196290001Sglebius 197290001Sglebius ATF_CHECK_EQ(a, 0); 198290001Sglebius isc_task_send(task1, &event); 199290001Sglebius 200290001Sglebius /* Second event: not privileged */ 201290001Sglebius event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, 202290001Sglebius set, &b, sizeof (isc_event_t)); 203290001Sglebius ATF_REQUIRE(event != NULL); 204290001Sglebius 205290001Sglebius ATF_CHECK_EQ(b, 0); 206290001Sglebius isc_task_send(task2, &event); 207290001Sglebius 208290001Sglebius /* Third event: privileged */ 209290001Sglebius event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, 210290001Sglebius set, &c, sizeof (isc_event_t)); 211290001Sglebius ATF_REQUIRE(event != NULL); 212290001Sglebius 213290001Sglebius ATF_CHECK_EQ(c, 0); 214290001Sglebius isc_task_send(task1, &event); 215290001Sglebius 216290001Sglebius /* Fourth event: privileged */ 217290001Sglebius event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, 218290001Sglebius set, &d, sizeof (isc_event_t)); 219290001Sglebius ATF_REQUIRE(event != NULL); 220290001Sglebius 221290001Sglebius ATF_CHECK_EQ(d, 0); 222290001Sglebius isc_task_send(task1, &event); 223290001Sglebius 224290001Sglebius /* Fifth event: not privileged */ 225290001Sglebius event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, 226290001Sglebius set, &e, sizeof (isc_event_t)); 227290001Sglebius ATF_REQUIRE(event != NULL); 228290001Sglebius 229290001Sglebius ATF_CHECK_EQ(e, 0); 230290001Sglebius isc_task_send(task2, &event); 231290001Sglebius 232290001Sglebius ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal); 233290001Sglebius isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged); 234290001Sglebius ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_privileged); 235290001Sglebius 236290001Sglebius#ifdef ISC_PLATFORM_USETHREADS 237290001Sglebius isc__taskmgr_resume(taskmgr); 238290001Sglebius#endif 239290001Sglebius 240290001Sglebius /* We're waiting for *all* variables to be set */ 241290001Sglebius while ((a == 0 || b == 0 || c == 0 || d == 0 || e == 0) && i++ < 5000) { 242290001Sglebius#ifndef ISC_PLATFORM_USETHREADS 243290001Sglebius while (isc__taskmgr_ready(taskmgr)) 244290001Sglebius isc__taskmgr_dispatch(taskmgr); 245290001Sglebius#endif 246290001Sglebius isc_test_nap(1000); 247290001Sglebius } 248290001Sglebius 249290001Sglebius /* 250290001Sglebius * We can't guarantee what order the events fire, but 251290001Sglebius * we do know the privileged tasks that set a, c, and d 252290001Sglebius * would have fired first. 253290001Sglebius */ 254290001Sglebius ATF_CHECK(a <= 3); 255290001Sglebius ATF_CHECK(c <= 3); 256290001Sglebius ATF_CHECK(d <= 3); 257290001Sglebius 258290001Sglebius /* ...and the non-privileged tasks that set b and e, last */ 259290001Sglebius ATF_CHECK(b >= 4); 260290001Sglebius ATF_CHECK(e >= 4); 261290001Sglebius 262290001Sglebius ATF_CHECK_EQ(counter, 6); 263290001Sglebius 264290001Sglebius isc_task_setprivilege(task1, ISC_FALSE); 265290001Sglebius ATF_CHECK(!isc_task_privilege(task1)); 266290001Sglebius 267290001Sglebius ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal); 268290001Sglebius 269290001Sglebius isc_task_destroy(&task1); 270290001Sglebius ATF_REQUIRE_EQ(task1, NULL); 271290001Sglebius isc_task_destroy(&task2); 272290001Sglebius ATF_REQUIRE_EQ(task2, NULL); 273290001Sglebius 274290001Sglebius isc_test_end(); 275290001Sglebius} 276290001Sglebius 277290001Sglebius/* 278290001Sglebius * Edge case: this tests that the task manager behaves as expected when 279290001Sglebius * we explicitly set it into normal mode *while* running privileged. 280290001Sglebius */ 281290001SglebiusATF_TC(privilege_drop); 282290001SglebiusATF_TC_HEAD(privilege_drop, tc) { 283290001Sglebius atf_tc_set_md_var(tc, "descr", "process privileged events"); 284290001Sglebius} 285290001SglebiusATF_TC_BODY(privilege_drop, tc) { 286290001Sglebius isc_result_t result; 287290001Sglebius isc_task_t *task1 = NULL, *task2 = NULL; 288290001Sglebius isc_event_t *event; 289290001Sglebius int a = -1, b = -1, c = -1, d = -1, e = -1; /* non valid states */ 290290001Sglebius int i = 0; 291290001Sglebius 292290001Sglebius UNUSED(tc); 293290001Sglebius 294290001Sglebius counter = 1; 295290001Sglebius result = isc_mutex_init(&set_lock); 296290001Sglebius ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 297290001Sglebius 298290001Sglebius result = isc_test_begin(NULL, ISC_TRUE); 299290001Sglebius ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 300290001Sglebius 301290001Sglebius#ifdef ISC_PLATFORM_USETHREADS 302290001Sglebius /* 303290001Sglebius * Pause the task manager so we can fill up the work queue 304290001Sglebius * without things happening while we do it. 305290001Sglebius */ 306290001Sglebius isc__taskmgr_pause(taskmgr); 307290001Sglebius#endif 308290001Sglebius 309290001Sglebius result = isc_task_create(taskmgr, 0, &task1); 310290001Sglebius ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 311290001Sglebius isc_task_setname(task1, "privileged", NULL); 312290001Sglebius ATF_CHECK(!isc_task_privilege(task1)); 313290001Sglebius isc_task_setprivilege(task1, ISC_TRUE); 314290001Sglebius ATF_CHECK(isc_task_privilege(task1)); 315290001Sglebius 316290001Sglebius result = isc_task_create(taskmgr, 0, &task2); 317290001Sglebius ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); 318290001Sglebius isc_task_setname(task2, "normal", NULL); 319290001Sglebius ATF_CHECK(!isc_task_privilege(task2)); 320290001Sglebius 321290001Sglebius /* First event: privileged */ 322290001Sglebius event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, 323290001Sglebius set_and_drop, &a, sizeof (isc_event_t)); 324290001Sglebius ATF_REQUIRE(event != NULL); 325290001Sglebius 326290001Sglebius ATF_CHECK_EQ(a, -1); 327290001Sglebius isc_task_send(task1, &event); 328290001Sglebius 329290001Sglebius /* Second event: not privileged */ 330290001Sglebius event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, 331290001Sglebius set_and_drop, &b, sizeof (isc_event_t)); 332290001Sglebius ATF_REQUIRE(event != NULL); 333290001Sglebius 334290001Sglebius ATF_CHECK_EQ(b, -1); 335290001Sglebius isc_task_send(task2, &event); 336290001Sglebius 337290001Sglebius /* Third event: privileged */ 338290001Sglebius event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, 339290001Sglebius set_and_drop, &c, sizeof (isc_event_t)); 340290001Sglebius ATF_REQUIRE(event != NULL); 341290001Sglebius 342290001Sglebius ATF_CHECK_EQ(c, -1); 343290001Sglebius isc_task_send(task1, &event); 344290001Sglebius 345290001Sglebius /* Fourth event: privileged */ 346290001Sglebius event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, 347290001Sglebius set_and_drop, &d, sizeof (isc_event_t)); 348290001Sglebius ATF_REQUIRE(event != NULL); 349290001Sglebius 350290001Sglebius ATF_CHECK_EQ(d, -1); 351290001Sglebius isc_task_send(task1, &event); 352290001Sglebius 353290001Sglebius /* Fifth event: not privileged */ 354290001Sglebius event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, 355290001Sglebius set_and_drop, &e, sizeof (isc_event_t)); 356290001Sglebius ATF_REQUIRE(event != NULL); 357290001Sglebius 358290001Sglebius ATF_CHECK_EQ(e, -1); 359290001Sglebius isc_task_send(task2, &event); 360290001Sglebius 361290001Sglebius ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal); 362290001Sglebius isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged); 363290001Sglebius ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_privileged); 364290001Sglebius 365290001Sglebius#ifdef ISC_PLATFORM_USETHREADS 366290001Sglebius isc__taskmgr_resume(taskmgr); 367290001Sglebius#endif 368290001Sglebius 369290001Sglebius /* We're waiting for all variables to be set. */ 370290001Sglebius while ((a == -1 || b == -1 || c == -1 || d == -1 || e == -1) && 371290001Sglebius i++ < 5000) { 372290001Sglebius#ifndef ISC_PLATFORM_USETHREADS 373290001Sglebius while (isc__taskmgr_ready(taskmgr)) 374290001Sglebius isc__taskmgr_dispatch(taskmgr); 375290001Sglebius#endif 376290001Sglebius isc_test_nap(1000); 377290001Sglebius } 378290001Sglebius 379290001Sglebius /* 380290001Sglebius * We can't guarantee what order the events fire, but 381290001Sglebius * we do know *exactly one* of the privileged tasks will 382290001Sglebius * have run in privileged mode... 383290001Sglebius */ 384290001Sglebius ATF_CHECK(a == isc_taskmgrmode_privileged || 385290001Sglebius c == isc_taskmgrmode_privileged || 386290001Sglebius d == isc_taskmgrmode_privileged); 387290001Sglebius ATF_CHECK(a + c + d == isc_taskmgrmode_privileged); 388290001Sglebius 389290001Sglebius /* ...and neither of the non-privileged tasks did... */ 390290001Sglebius ATF_CHECK(b == isc_taskmgrmode_normal || e == isc_taskmgrmode_normal); 391290001Sglebius 392290001Sglebius /* ...but all five of them did run. */ 393290001Sglebius ATF_CHECK_EQ(counter, 6); 394290001Sglebius 395290001Sglebius ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal); 396290001Sglebius 397290001Sglebius isc_task_destroy(&task1); 398290001Sglebius ATF_REQUIRE_EQ(task1, NULL); 399290001Sglebius isc_task_destroy(&task2); 400290001Sglebius ATF_REQUIRE_EQ(task2, NULL); 401290001Sglebius 402290001Sglebius isc_test_end(); 403290001Sglebius} 404290001Sglebius 405290001Sglebius/* 406290001Sglebius * Main 407290001Sglebius */ 408290001SglebiusATF_TP_ADD_TCS(tp) { 409290001Sglebius ATF_TP_ADD_TC(tp, create_task); 410290001Sglebius ATF_TP_ADD_TC(tp, all_events); 411290001Sglebius ATF_TP_ADD_TC(tp, privileged_events); 412290001Sglebius ATF_TP_ADD_TC(tp, privilege_drop); 413290001Sglebius 414290001Sglebius return (atf_no_error()); 415290001Sglebius} 416290001Sglebius 417