1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <atomic.h> 28 #include <errno.h> 29 #include <execinfo.h> 30 #include <libuutil.h> 31 #include <pthread.h> 32 #include <signal.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <strings.h> 36 #include <syslog.h> 37 #include <sys/time.h> 38 #include <unistd.h> 39 40 #include "conditions.h" 41 #include "events.h" 42 #include "objects.h" 43 #include "util.h" 44 45 /* 46 * events.c - contains routines which create/destroy event sources, 47 * handle the event queue and process events from that queue. 48 */ 49 50 /* Add new event sources here. */ 51 struct nwamd_event_source { 52 char *name; 53 void (*events_init)(void); 54 void (*events_fini)(void); 55 } event_sources[] = { 56 { "routing_events", 57 nwamd_routing_events_init, nwamd_routing_events_fini }, 58 { "sysevent_events", 59 nwamd_sysevent_events_init, nwamd_sysevent_events_fini }, 60 }; 61 62 /* Counter for event ids */ 63 static uint64_t event_id_counter = 0; 64 65 static uu_list_pool_t *event_pool = NULL; 66 static uu_list_t *event_queue = NULL; 67 static pthread_mutex_t event_queue_mutex = PTHREAD_MUTEX_INITIALIZER; 68 static pthread_cond_t event_queue_cond = PTHREAD_COND_INITIALIZER; 69 70 static int nwamd_event_compare(const void *, const void *, void *); 71 72 static const char * 73 nwamd_event_name(int event_type) 74 { 75 if (event_type <= NWAM_EVENT_MAX) 76 return (nwam_event_type_to_string(event_type)); 77 78 switch (event_type) { 79 case NWAM_EVENT_TYPE_OBJECT_INIT: 80 return ("OBJECT_INIT"); 81 case NWAM_EVENT_TYPE_OBJECT_FINI: 82 return ("OBJECT_FINI"); 83 case NWAM_EVENT_TYPE_TIMED_CHECK_CONDITIONS: 84 return ("TIMED_CHECK_CONDITIONS"); 85 case NWAM_EVENT_TYPE_TRIGGERED_CHECK_CONDITIONS: 86 return ("TRIGGERED_CHECK_CONDITIONS"); 87 case NWAM_EVENT_TYPE_NCU_CHECK: 88 return ("NCU_CHECK"); 89 case NWAM_EVENT_TYPE_TIMER: 90 return ("TIMER"); 91 case NWAM_EVENT_TYPE_UPGRADE: 92 return ("UPGRADE"); 93 case NWAM_EVENT_TYPE_PERIODIC_SCAN: 94 return ("PERIODIC_SCAN"); 95 case NWAM_EVENT_TYPE_QUEUE_QUIET: 96 return ("QUEUE_QUIET"); 97 default: 98 return ("N/A"); 99 } 100 } 101 102 void 103 nwamd_event_sources_init(void) 104 { 105 int i; 106 107 /* 108 * Now we can safely initialize event sources. 109 */ 110 for (i = 0; 111 i < sizeof (event_sources) / sizeof (struct nwamd_event_source); 112 i++) { 113 if (event_sources[i].events_init != NULL) 114 event_sources[i].events_init(); 115 } 116 } 117 118 void 119 nwamd_event_sources_fini(void) 120 { 121 int i; 122 123 for (i = 0; 124 i < sizeof (event_sources) / sizeof (struct nwamd_event_source); 125 i++) { 126 if (event_sources[i].events_init != NULL) 127 event_sources[i].events_fini(); 128 } 129 } 130 131 /* 132 * Comparison function for events, passed in as callback to 133 * uu_list_pool_create(). Compare by time, so that timer 134 * event queue can be sorted by nearest time to present. 135 */ 136 /* ARGSUSED */ 137 static int 138 nwamd_event_compare(const void *l_arg, const void *r_arg, void *private) 139 { 140 nwamd_event_t l = (nwamd_event_t)l_arg; 141 nwamd_event_t r = (nwamd_event_t)r_arg; 142 int rv; 143 144 rv = l->event_time.tv_sec - r->event_time.tv_sec; 145 if (rv == 0) 146 rv = l->event_time.tv_nsec - r->event_time.tv_nsec; 147 148 return (rv); 149 } 150 151 void 152 nwamd_event_queue_init(void) 153 { 154 event_pool = uu_list_pool_create("event_queue_pool", 155 sizeof (struct nwamd_event), 156 offsetof(struct nwamd_event, event_node), 157 nwamd_event_compare, UU_LIST_POOL_DEBUG); 158 if (event_pool == NULL) 159 pfail("uu_list_pool_create failed with error %d", uu_error()); 160 event_queue = uu_list_create(event_pool, NULL, UU_LIST_SORTED); 161 if (event_queue == NULL) 162 pfail("uu_list_create failed with error %d", uu_error()); 163 } 164 165 void 166 nwamd_event_queue_fini(void) 167 { 168 void *cookie = NULL; 169 nwamd_event_t event; 170 171 while ((event = uu_list_teardown(event_queue, &cookie)) != NULL) 172 nwamd_event_fini(event); 173 uu_list_destroy(event_queue); 174 if (event_pool != NULL) 175 uu_list_pool_destroy(event_pool); 176 } 177 178 nwamd_event_t 179 nwamd_event_init(int32_t type, nwam_object_type_t object_type, 180 size_t size, const char *object_name) 181 { 182 nwamd_event_t event; 183 184 event = calloc(1, sizeof (struct nwamd_event)); 185 if (event == NULL) { 186 nlog(LOG_ERR, "nwamd_event_init: could not create %s event for " 187 "object %s", nwamd_event_name(type), 188 object_name != NULL ? object_name : "<no object>"); 189 return (NULL); 190 } 191 192 /* Is this an externally-visible event? */ 193 if (type <= NWAM_EVENT_MAX) { 194 event->event_send = B_TRUE; 195 event->event_msg = calloc(1, sizeof (struct nwam_event) + size); 196 if (event->event_msg == NULL) { 197 nlog(LOG_ERR, 198 "nwamd_event_init: could not create %s event", 199 nwamd_event_name(type)); 200 free(event); 201 return (NULL); 202 } 203 event->event_msg->nwe_type = type; 204 event->event_msg->nwe_size = sizeof (struct nwam_event) + size; 205 } else { 206 event->event_send = B_FALSE; 207 event->event_msg = NULL; 208 } 209 210 event->event_type = type; 211 212 if (object_name != NULL) { 213 (void) strlcpy(event->event_object, object_name, 214 NWAM_MAX_NAME_LEN); 215 event->event_object_type = object_type; 216 } else { 217 event->event_object[0] = '\0'; 218 } 219 220 /* Set event id */ 221 event->event_id = atomic_add_64_nv(&event_id_counter, 1); 222 (void) clock_gettime(CLOCK_REALTIME, &event->event_time); 223 224 return (event); 225 } 226 227 void 228 nwamd_event_do_not_send(nwamd_event_t event) 229 { 230 nlog(LOG_DEBUG, "nwamd_event_do_not_send: cancelling delivery of " 231 "event %s for object %s", nwamd_event_name(event->event_type), 232 event->event_object[0] != '\0' ? 233 event->event_object : "<no object>"); 234 event->event_send = B_FALSE; 235 } 236 237 void 238 nwamd_event_fini(nwamd_event_t event) 239 { 240 if (event != NULL) { 241 free(event->event_msg); 242 free(event); 243 } 244 } 245 246 nwamd_event_t 247 nwamd_event_init_object_action(nwam_object_type_t object_type, 248 const char *object_name, const char *parent_name, 249 nwam_action_t object_action) 250 { 251 nwamd_event_t event; 252 253 event = nwamd_event_init(NWAM_EVENT_TYPE_OBJECT_ACTION, 254 object_type, 0, object_name); 255 if (event == NULL) 256 return (NULL); 257 258 event->event_msg->nwe_data.nwe_object_action.nwe_action = object_action; 259 event->event_msg->nwe_data.nwe_object_action.nwe_object_type = 260 object_type; 261 (void) strlcpy(event->event_msg->nwe_data.nwe_object_action.nwe_name, 262 object_name, 263 sizeof (event->event_msg->nwe_data.nwe_object_action.nwe_name)); 264 if (parent_name == NULL) { 265 event->event_msg->nwe_data.nwe_object_action.nwe_parent[0] = 266 '\0'; 267 return (event); 268 } 269 (void) strlcpy 270 (event->event_msg->nwe_data.nwe_object_action.nwe_parent, 271 parent_name, 272 sizeof (event->event_msg->nwe_data.nwe_object_action.nwe_parent)); 273 return (event); 274 } 275 276 nwamd_event_t 277 nwamd_event_init_object_state(nwam_object_type_t object_type, 278 const char *object_name, nwam_state_t state, nwam_aux_state_t aux_state) 279 { 280 nwamd_event_t event; 281 282 event = nwamd_event_init(NWAM_EVENT_TYPE_OBJECT_STATE, 283 object_type, 0, object_name); 284 if (event == NULL) 285 return (NULL); 286 287 event->event_msg->nwe_data.nwe_object_state.nwe_state = state; 288 event->event_msg->nwe_data.nwe_object_state.nwe_aux_state = aux_state; 289 event->event_msg->nwe_data.nwe_object_state.nwe_object_type = 290 object_type; 291 (void) strlcpy(event->event_msg->nwe_data.nwe_object_state.nwe_name, 292 object_name, 293 sizeof (event->event_msg->nwe_data.nwe_object_state.nwe_name)); 294 295 return (event); 296 } 297 298 nwamd_event_t 299 nwamd_event_init_priority_group_change(int64_t priority) 300 { 301 nwamd_event_t event; 302 303 event = nwamd_event_init(NWAM_EVENT_TYPE_PRIORITY_GROUP, 304 NWAM_OBJECT_TYPE_UNKNOWN, 0, NULL); 305 if (event == NULL) 306 return (NULL); 307 308 event->event_msg->nwe_data.nwe_priority_group_info.nwe_priority = 309 priority; 310 311 return (event); 312 } 313 314 nwamd_event_t 315 nwamd_event_init_link_action(const char *name, nwam_action_t link_action) 316 { 317 nwamd_event_t event; 318 nwam_error_t err; 319 char *object_name; 320 321 if ((err = nwam_ncu_name_to_typed_name(name, NWAM_NCU_TYPE_LINK, 322 &object_name)) != NWAM_SUCCESS) { 323 nlog(LOG_ERR, "nwamd_event_init_link_action: " 324 "nwam_ncu_name_to_typed_name: %s", 325 nwam_strerror(err)); 326 return (NULL); 327 } 328 event = nwamd_event_init(NWAM_EVENT_TYPE_LINK_ACTION, 329 NWAM_OBJECT_TYPE_NCU, 0, object_name); 330 free(object_name); 331 if (event == NULL) 332 return (NULL); 333 334 (void) strlcpy(event->event_msg->nwe_data.nwe_link_action.nwe_name, 335 name, 336 sizeof (event->event_msg->nwe_data.nwe_link_action.nwe_name)); 337 event->event_msg->nwe_data.nwe_link_action.nwe_action = link_action; 338 339 return (event); 340 } 341 342 nwamd_event_t 343 nwamd_event_init_link_state(const char *name, boolean_t up) 344 { 345 nwamd_event_t event; 346 nwam_error_t err; 347 char *object_name; 348 349 if ((err = nwam_ncu_name_to_typed_name(name, NWAM_NCU_TYPE_LINK, 350 &object_name)) != NWAM_SUCCESS) { 351 nlog(LOG_ERR, "nwamd_event_init_link_state: " 352 "nwam_ncu_name_to_typed_name: %s", 353 nwam_strerror(err)); 354 return (NULL); 355 } 356 357 event = nwamd_event_init(NWAM_EVENT_TYPE_LINK_STATE, 358 NWAM_OBJECT_TYPE_NCU, 0, object_name); 359 free(object_name); 360 if (event == NULL) 361 return (NULL); 362 363 (void) strlcpy(event->event_msg->nwe_data.nwe_link_state.nwe_name, name, 364 sizeof (event->event_msg->nwe_data.nwe_link_state.nwe_name)); 365 event->event_msg->nwe_data.nwe_link_state.nwe_link_up = up; 366 367 return (event); 368 } 369 370 nwamd_event_t 371 nwamd_event_init_if_state(const char *linkname, uint32_t flags, 372 uint32_t addr_added, uint32_t index, struct sockaddr *addr) 373 { 374 nwamd_event_t event; 375 nwam_error_t err; 376 char *object_name; 377 378 /* linkname does not contain the lifnum */ 379 if ((err = nwam_ncu_name_to_typed_name(linkname, 380 NWAM_NCU_TYPE_INTERFACE, &object_name)) != NWAM_SUCCESS) { 381 nlog(LOG_ERR, "nwamd_event_init_if_state: " 382 "nwam_ncu_name_to_typed_name: %s", 383 nwam_strerror(err)); 384 return (NULL); 385 } 386 387 event = nwamd_event_init(NWAM_EVENT_TYPE_IF_STATE, 388 NWAM_OBJECT_TYPE_NCU, 0, object_name); 389 free(object_name); 390 if (event == NULL) 391 return (NULL); 392 393 (void) strlcpy(event->event_msg->nwe_data.nwe_if_state.nwe_name, 394 linkname, 395 sizeof (event->event_msg->nwe_data.nwe_if_state.nwe_name)); 396 event->event_msg->nwe_data.nwe_if_state.nwe_flags = flags; 397 event->event_msg->nwe_data.nwe_if_state.nwe_index = index; 398 event->event_msg->nwe_data.nwe_if_state.nwe_addr_added = addr_added; 399 event->event_msg->nwe_data.nwe_if_state.nwe_addr_valid = (addr != NULL); 400 401 if (addr != NULL) { 402 bcopy(addr, &(event->event_msg->nwe_data.nwe_if_state.nwe_addr), 403 addr->sa_family == AF_INET ? sizeof (struct sockaddr_in) : 404 sizeof (struct sockaddr_in6)); 405 } 406 407 return (event); 408 } 409 410 nwamd_event_t 411 nwamd_event_init_wlan(const char *name, int32_t type, boolean_t connected, 412 nwam_wlan_t *wlans, uint_t num_wlans) 413 { 414 size_t size = 0; 415 char *object_name; 416 nwamd_event_t event; 417 nwam_error_t err; 418 419 switch (type) { 420 case NWAM_EVENT_TYPE_WLAN_SCAN_REPORT: 421 case NWAM_EVENT_TYPE_WLAN_NEED_CHOICE: 422 size = sizeof (nwam_wlan_t) * (num_wlans - 1); 423 break; 424 case NWAM_EVENT_TYPE_WLAN_NEED_KEY: 425 case NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT: 426 break; 427 default: 428 nlog(LOG_ERR, "nwamd_event_init_wlan: unexpected " 429 "event type %s (%d)", nwamd_event_name(type), type); 430 return (NULL); 431 } 432 if ((err = nwam_ncu_name_to_typed_name(name, NWAM_NCU_TYPE_LINK, 433 &object_name)) != NWAM_SUCCESS) { 434 nlog(LOG_ERR, "nwamd_event_init_wlan: " 435 "nwam_ncu_name_to_typed_name: %s", 436 nwam_strerror(err)); 437 return (NULL); 438 } 439 440 event = nwamd_event_init(type, NWAM_OBJECT_TYPE_NCU, size, object_name); 441 free(object_name); 442 if (event == NULL) 443 return (NULL); 444 445 (void) strlcpy(event->event_msg->nwe_data.nwe_wlan_info.nwe_name, name, 446 sizeof (event->event_msg->nwe_data.nwe_wlan_info.nwe_name)); 447 event->event_msg->nwe_data.nwe_wlan_info.nwe_connected = connected; 448 event->event_msg->nwe_data.nwe_wlan_info.nwe_num_wlans = num_wlans; 449 450 /* copy the wlans */ 451 (void) memcpy(event->event_msg->nwe_data.nwe_wlan_info.nwe_wlans, wlans, 452 num_wlans * sizeof (nwam_wlan_t)); 453 454 return (event); 455 } 456 457 nwamd_event_t 458 nwamd_event_init_ncu_check(void) 459 { 460 return (nwamd_event_init(NWAM_EVENT_TYPE_NCU_CHECK, 461 NWAM_OBJECT_TYPE_NCP, 0, NULL)); 462 } 463 464 nwamd_event_t 465 nwamd_event_init_init(void) 466 { 467 return (nwamd_event_init(NWAM_EVENT_TYPE_INIT, 468 NWAM_OBJECT_TYPE_UNKNOWN, 0, NULL)); 469 } 470 471 nwamd_event_t 472 nwamd_event_init_shutdown(void) 473 { 474 return (nwamd_event_init(NWAM_EVENT_TYPE_SHUTDOWN, 475 NWAM_OBJECT_TYPE_UNKNOWN, 0, NULL)); 476 } 477 478 /* 479 * Add event to the event list. 480 */ 481 void 482 nwamd_event_enqueue(nwamd_event_t event) 483 { 484 nwamd_event_enqueue_timed(event, 0); 485 } 486 487 /* 488 * Schedule an event to be added to the event list for future processing. 489 * The event will be scheduled in delta_seconds seconds mod schedule delay and 490 * time resolution. 491 */ 492 void 493 nwamd_event_enqueue_timed(nwamd_event_t event, int delta_seconds) 494 { 495 uu_list_index_t idx; 496 497 nlog(LOG_DEBUG, "enqueueing event %lld %d (%s) for object %s in %ds", 498 event->event_id, event->event_type, 499 nwamd_event_name(event->event_type), 500 event->event_object[0] != 0 ? event->event_object : "none", 501 delta_seconds); 502 503 (void) clock_gettime(CLOCK_REALTIME, &event->event_time); 504 event->event_time.tv_sec += delta_seconds; 505 506 uu_list_node_init(event, &event->event_node, event_pool); 507 508 (void) pthread_mutex_lock(&event_queue_mutex); 509 510 /* 511 * Find appropriate location to insert the event based on time. 512 */ 513 (void) uu_list_find(event_queue, event, NULL, &idx); 514 (void) uu_list_insert(event_queue, event, idx); 515 516 (void) pthread_cond_signal(&event_queue_cond); 517 (void) pthread_mutex_unlock(&event_queue_mutex); 518 } 519 520 /* 521 * Is the specified event enqueued on the event (or pending event queue) 522 * for execution in when seconds? An object may be specified also. 523 */ 524 boolean_t 525 nwamd_event_enqueued(int32_t event_type, nwam_object_type_t object_type, 526 const char *object) 527 { 528 nwamd_event_t event; 529 530 (void) pthread_mutex_lock(&event_queue_mutex); 531 for (event = uu_list_first(event_queue); 532 event != NULL; 533 event = uu_list_next(event_queue, event)) { 534 if (event->event_type != event_type) 535 continue; 536 if (object_type != NWAM_OBJECT_TYPE_UNKNOWN && 537 event->event_object_type != object_type) 538 continue; 539 if (object != NULL && strcmp(object, event->event_object) != 0) 540 continue; 541 (void) pthread_mutex_unlock(&event_queue_mutex); 542 return (B_TRUE); 543 } 544 (void) pthread_mutex_unlock(&event_queue_mutex); 545 546 return (B_FALSE); 547 } 548 549 /* 550 * Is the time in the past. 551 */ 552 static boolean_t 553 in_past(struct timespec t) 554 { 555 struct timespec now; 556 557 (void) clock_gettime(CLOCK_REALTIME, &now); 558 if (t.tv_sec < now.tv_sec) 559 return (B_TRUE); 560 if (t.tv_sec > now.tv_sec) 561 return (B_FALSE); 562 if (t.tv_nsec < now.tv_nsec) 563 return (B_TRUE); 564 return (B_FALSE); 565 } 566 567 /* 568 * Remove event at head of event list for processing. This takes a number of 569 * nanoseconds to wait. If the number is 0 then it blocks. If there is 570 * nothing on the queue then it returns an event which says that the queue 571 * is quiet. 572 */ 573 static nwamd_event_t 574 nwamd_event_dequeue(long nsec) 575 { 576 nwamd_event_t event; 577 578 (void) pthread_mutex_lock(&event_queue_mutex); 579 event = uu_list_first(event_queue); 580 if (event == NULL && nsec == 0) { 581 do { 582 (void) pthread_cond_wait(&event_queue_cond, 583 &event_queue_mutex); 584 } while ((event = uu_list_first(event_queue)) == NULL); 585 } else { 586 struct timespec waitcap; 587 588 if (nsec != 0) { 589 (void) clock_gettime(CLOCK_REALTIME, &waitcap); 590 waitcap.tv_nsec += nsec; 591 waitcap.tv_sec += NSEC_TO_SEC(waitcap.tv_nsec); 592 waitcap.tv_nsec = NSEC_TO_FRACNSEC(waitcap.tv_nsec); 593 } 594 595 /* 596 * Keep going as long as the first event hasn't matured and 597 * we havn't passed our maximum wait time. 598 */ 599 while ((event == NULL || !in_past(event->event_time)) && 600 (nsec == 0 || !in_past(waitcap))) { 601 struct timespec eventwait; 602 603 /* 604 * Three cases: 605 * no maximum waittime - just use the event 606 * both an event and cap - take the least one 607 * just a maximum waittime - use it 608 */ 609 if (nsec == 0) { 610 eventwait = event->event_time; 611 } else if (event != NULL) { 612 uint64_t diff; 613 diff = SEC_TO_NSEC(event->event_time.tv_sec - 614 waitcap.tv_sec) + 615 event->event_time.tv_nsec - waitcap.tv_nsec; 616 617 if (diff > 0) 618 eventwait = waitcap; 619 else 620 eventwait = event->event_time; 621 } else { 622 /* 623 * Note that if the event is NULL then nsec is 624 * nonzero and waitcap is valid. 625 */ 626 eventwait = waitcap; 627 } 628 629 (void) pthread_cond_timedwait(&event_queue_cond, 630 &event_queue_mutex, &eventwait); 631 event = uu_list_first(event_queue); 632 } 633 } 634 635 /* 636 * At this point we've met the guard contition of the while loop. 637 * The event at the top of the queue might be mature in which case 638 * we use it. Otherwise we hit our cap and we need to enqueue a 639 * quiesced queue event. 640 */ 641 if (event != NULL && in_past(event->event_time)) { 642 uu_list_remove(event_queue, event); 643 uu_list_node_fini(event, &event->event_node, event_pool); 644 } else { 645 event = nwamd_event_init(NWAM_EVENT_TYPE_QUEUE_QUIET, 646 NWAM_OBJECT_TYPE_UNKNOWN, 0, NULL); 647 } 648 649 if (event != NULL) 650 nlog(LOG_DEBUG, 651 "dequeueing event %lld of type %d (%s) for object %s", 652 event->event_id, event->event_type, 653 nwamd_event_name(event->event_type), 654 event->event_object[0] != 0 ? event->event_object : 655 "none"); 656 657 (void) pthread_mutex_unlock(&event_queue_mutex); 658 659 return (event); 660 } 661 662 void 663 nwamd_event_send(nwam_event_t event_msg) 664 { 665 nwam_error_t err; 666 667 if (shutting_down && event_msg->nwe_type != NWAM_EVENT_TYPE_SHUTDOWN) { 668 nlog(LOG_DEBUG, "nwamd_event_send: tossing event as nwamd " 669 "is shutting down"); 670 return; 671 } 672 673 err = nwam_event_send(event_msg); 674 675 if (err != NWAM_SUCCESS) { 676 nlog(LOG_ERR, "nwamd_event_send: nwam_event_send: %s", 677 nwam_strerror(err)); 678 } 679 } 680 681 /* 682 * Run state machine for object. Method is run if 683 * - event method is non-null 684 * - event method is valid for current object state (determined by 685 * ORing the current state against the set of valid states for the method). 686 * 687 * If these criteria are met, the method is run. 688 */ 689 static void 690 nwamd_event_run_method(nwamd_event_t event) 691 { 692 nwamd_event_method_t *event_methods; 693 int i; 694 695 event_methods = nwamd_object_event_methods(event->event_object_type); 696 697 /* If we're shutting down, only fini events are accepted for objects */ 698 if (shutting_down && event->event_type != NWAM_EVENT_TYPE_OBJECT_FINI) { 699 nlog(LOG_DEBUG, "nwamd_event_run_method: tossing non-fini " 700 "event %s for object %s", 701 nwamd_event_name(event->event_type), event->event_object); 702 return; 703 } 704 705 for (i = 0; 706 event_methods[i].event_type != NWAM_EVENT_TYPE_NOOP; 707 i++) { 708 if (event_methods[i].event_type == 709 event->event_type && 710 event_methods[i].event_method != NULL) { 711 nlog(LOG_DEBUG, 712 "(%p) %s: running method for event %s", 713 (void *)event, event->event_object, 714 nwamd_event_name(event->event_type)); 715 /* run method */ 716 event_methods[i].event_method(event); 717 return; 718 } 719 } 720 nlog(LOG_DEBUG, "(%p) %s: no matching method for event %d (%s)", 721 (void *)event, event->event_object, event->event_type, 722 nwamd_event_name(event->event_type)); 723 } 724 725 /* 726 * Called when we are checking to see what should be activated. First activate 727 * all of the manual NCUs. Then see if we can find a valid priority group. 728 * If we can, activate it. Otherwise try all the priority groups starting 729 * with the lowest one that makes sense. 730 */ 731 static void 732 nwamd_activate_ncus(void) { 733 int64_t prio = INVALID_PRIORITY_GROUP; 734 boolean_t selected; 735 736 nwamd_ncp_activate_manual_ncus(); 737 selected = nwamd_ncp_check_priority_group(&prio); 738 if (selected) { 739 /* 740 * Activate chosen priority group and stop anything going on in 741 * lesser priority groups. 742 */ 743 nwamd_ncp_activate_priority_group(prio); 744 nwamd_ncp_deactivate_priority_group_all(prio + 1); 745 } else { 746 /* 747 * Nothing unique could be started so try them all. Once one 748 * of them gets into a reasonable state then we will prune 749 * everything below it (see first part of this conditional). 750 */ 751 int64_t oldprio = INVALID_PRIORITY_GROUP; 752 while (nwamd_ncp_find_next_priority_group(++oldprio, &prio)) { 753 nwamd_ncp_activate_priority_group(prio); 754 oldprio = prio; 755 } 756 } 757 } 758 759 /* 760 * Event handler thread 761 * 762 * The complexity in this code comes about from wanting to delay the decision 763 * making process until after bursts of events. Keep roughly polling (waiting 764 * for .1s) until we see the queue quiet event and then block. 765 */ 766 void 767 nwamd_event_handler(void) 768 { 769 boolean_t got_shutdown_event = B_FALSE; 770 boolean_t check_conditions = B_FALSE; 771 boolean_t ncu_check = B_FALSE; 772 int queue_quiet_time = 0; 773 nwamd_event_t event; 774 775 /* 776 * Dequeue events and process them. In most cases, events have 777 * an assocated object type, and we use this to retrieve 778 * the function that will process the event. 779 */ 780 while (!got_shutdown_event) { 781 event = nwamd_event_dequeue(queue_quiet_time); 782 /* keep pulling events as long as they are close together */ 783 queue_quiet_time = SEC_TO_NSEC(1)/10; 784 785 /* 786 * This is an event with no associated object. 787 */ 788 if (event->event_object[0] == '\0') { 789 switch (event->event_type) { 790 case NWAM_EVENT_TYPE_NOOP: 791 case NWAM_EVENT_TYPE_INIT: 792 /* 793 * The only action for an INIT event 794 * is to relay it to event listeners, 795 * which is done below. 796 */ 797 break; 798 case NWAM_EVENT_TYPE_PRIORITY_GROUP: 799 (void) pthread_mutex_lock(&active_ncp_mutex); 800 current_ncu_priority_group = 801 event->event_msg->nwe_data. 802 nwe_priority_group_info.nwe_priority; 803 (void) pthread_mutex_unlock(&active_ncp_mutex); 804 break; 805 case NWAM_EVENT_TYPE_TIMED_CHECK_CONDITIONS: 806 if (!shutting_down) { 807 nwamd_set_timed_check_all_conditions(); 808 check_conditions = B_TRUE; 809 } 810 break; 811 case NWAM_EVENT_TYPE_TRIGGERED_CHECK_CONDITIONS: 812 if (!shutting_down) 813 check_conditions = B_TRUE; 814 break; 815 case NWAM_EVENT_TYPE_NCU_CHECK: 816 if (!shutting_down) 817 ncu_check = B_TRUE; 818 break; 819 case NWAM_EVENT_TYPE_UPGRADE: 820 if (!shutting_down) { 821 /* 822 * Upgrade events have no associated 823 * object. 824 */ 825 nwamd_event_run_method(event); 826 } 827 break; 828 case NWAM_EVENT_TYPE_SHUTDOWN: 829 got_shutdown_event = B_TRUE; 830 break; 831 832 /* 833 * We want to delay processing of condition and ncu 834 * checking until after short bursts of events. So we 835 * keep track of times we've scheduled checking and 836 * wait for the queue to quiesce. 837 */ 838 case NWAM_EVENT_TYPE_QUEUE_QUIET: 839 queue_quiet_time = 0; /* now we can block */ 840 if (!shutting_down && check_conditions) { 841 nwamd_check_all_conditions(); 842 check_conditions = B_FALSE; 843 } 844 845 if (!shutting_down && ncu_check) { 846 nwamd_activate_ncus(); 847 ncu_check = B_FALSE; 848 } 849 break; 850 851 default: 852 nlog(LOG_ERR, 853 "event %d (%s)had no object associated " 854 "with it", event->event_type, 855 nwamd_event_name(event->event_type)); 856 break; 857 } 858 } else { 859 /* 860 * Event has an associated object - run event method 861 * for that object type (if any). 862 */ 863 nwamd_event_run_method(event); 864 } 865 /* 866 * Send associated message to listeners if event type is 867 * externally visible. 868 */ 869 if (event->event_send) 870 nwamd_event_send(event->event_msg); 871 872 nwamd_event_fini(event); 873 } 874 /* If we get here, we got a shutdown event. */ 875 nwamd_event_queue_fini(); 876 nwamd_object_lists_fini(); 877 } 878