1*12Sigor@sysoev.ru 2*12Sigor@sysoev.ru /* 3*12Sigor@sysoev.ru * Copyright (C) Igor Sysoev 4*12Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 5*12Sigor@sysoev.ru */ 6*12Sigor@sysoev.ru 7*12Sigor@sysoev.ru #include <nxt_main.h> 8*12Sigor@sysoev.ru 9*12Sigor@sysoev.ru 10*12Sigor@sysoev.ru /* 11*12Sigor@sysoev.ru * The event ports have been introduced in Solaris 10. 12*12Sigor@sysoev.ru * The PORT_SOURCE_MQ and PORT_SOURCE_FILE sources have 13*12Sigor@sysoev.ru * been added in OpenSolaris. 14*12Sigor@sysoev.ru */ 15*12Sigor@sysoev.ru 16*12Sigor@sysoev.ru 17*12Sigor@sysoev.ru static nxt_int_t nxt_eventport_create(nxt_event_engine_t *engine, 18*12Sigor@sysoev.ru nxt_uint_t mchanges, nxt_uint_t mevents); 19*12Sigor@sysoev.ru static void nxt_eventport_free(nxt_event_engine_t *engine); 20*12Sigor@sysoev.ru static void nxt_eventport_enable(nxt_event_engine_t *engine, 21*12Sigor@sysoev.ru nxt_fd_event_t *ev); 22*12Sigor@sysoev.ru static void nxt_eventport_disable(nxt_event_engine_t *engine, 23*12Sigor@sysoev.ru nxt_fd_event_t *ev); 24*12Sigor@sysoev.ru static nxt_bool_t nxt_eventport_close(nxt_event_engine_t *engine, 25*12Sigor@sysoev.ru nxt_fd_event_t *ev); 26*12Sigor@sysoev.ru static void nxt_eventport_enable_read(nxt_event_engine_t *engine, 27*12Sigor@sysoev.ru nxt_fd_event_t *ev); 28*12Sigor@sysoev.ru static void nxt_eventport_enable_write(nxt_event_engine_t *engine, 29*12Sigor@sysoev.ru nxt_fd_event_t *ev); 30*12Sigor@sysoev.ru static void nxt_eventport_enable_event(nxt_event_engine_t *engine, 31*12Sigor@sysoev.ru nxt_fd_event_t *ev, nxt_uint_t events); 32*12Sigor@sysoev.ru static void nxt_eventport_disable_read(nxt_event_engine_t *engine, 33*12Sigor@sysoev.ru nxt_fd_event_t *ev); 34*12Sigor@sysoev.ru static void nxt_eventport_disable_write(nxt_event_engine_t *engine, 35*12Sigor@sysoev.ru nxt_fd_event_t *ev); 36*12Sigor@sysoev.ru static void nxt_eventport_disable_event(nxt_event_engine_t *engine, 37*12Sigor@sysoev.ru nxt_fd_event_t *ev); 38*12Sigor@sysoev.ru static nxt_int_t nxt_eventport_commit_changes(nxt_event_engine_t *engine); 39*12Sigor@sysoev.ru static void nxt_eventport_error_handler(nxt_task_t *task, void *obj, 40*12Sigor@sysoev.ru void *data); 41*12Sigor@sysoev.ru static void nxt_eventport_block_read(nxt_event_engine_t *engine, 42*12Sigor@sysoev.ru nxt_fd_event_t *ev); 43*12Sigor@sysoev.ru static void nxt_eventport_block_write(nxt_event_engine_t *engine, 44*12Sigor@sysoev.ru nxt_fd_event_t *ev); 45*12Sigor@sysoev.ru static void nxt_eventport_oneshot_read(nxt_event_engine_t *engine, 46*12Sigor@sysoev.ru nxt_fd_event_t *ev); 47*12Sigor@sysoev.ru static void nxt_eventport_oneshot_write(nxt_event_engine_t *engine, 48*12Sigor@sysoev.ru nxt_fd_event_t *ev); 49*12Sigor@sysoev.ru static void nxt_eventport_enable_accept(nxt_event_engine_t *engine, 50*12Sigor@sysoev.ru nxt_fd_event_t *ev); 51*12Sigor@sysoev.ru static nxt_int_t nxt_eventport_enable_post(nxt_event_engine_t *engine, 52*12Sigor@sysoev.ru nxt_work_handler_t handler); 53*12Sigor@sysoev.ru static void nxt_eventport_signal(nxt_event_engine_t *engine, nxt_uint_t signo); 54*12Sigor@sysoev.ru static void nxt_eventport_poll(nxt_event_engine_t *engine, 55*12Sigor@sysoev.ru nxt_msec_t timeout); 56*12Sigor@sysoev.ru 57*12Sigor@sysoev.ru 58*12Sigor@sysoev.ru const nxt_event_interface_t nxt_eventport_engine = { 59*12Sigor@sysoev.ru "eventport", 60*12Sigor@sysoev.ru nxt_eventport_create, 61*12Sigor@sysoev.ru nxt_eventport_free, 62*12Sigor@sysoev.ru nxt_eventport_enable, 63*12Sigor@sysoev.ru nxt_eventport_disable, 64*12Sigor@sysoev.ru nxt_eventport_disable, 65*12Sigor@sysoev.ru nxt_eventport_close, 66*12Sigor@sysoev.ru nxt_eventport_enable_read, 67*12Sigor@sysoev.ru nxt_eventport_enable_write, 68*12Sigor@sysoev.ru nxt_eventport_disable_read, 69*12Sigor@sysoev.ru nxt_eventport_disable_write, 70*12Sigor@sysoev.ru nxt_eventport_block_read, 71*12Sigor@sysoev.ru nxt_eventport_block_write, 72*12Sigor@sysoev.ru nxt_eventport_oneshot_read, 73*12Sigor@sysoev.ru nxt_eventport_oneshot_write, 74*12Sigor@sysoev.ru nxt_eventport_enable_accept, 75*12Sigor@sysoev.ru NULL, 76*12Sigor@sysoev.ru NULL, 77*12Sigor@sysoev.ru nxt_eventport_enable_post, 78*12Sigor@sysoev.ru nxt_eventport_signal, 79*12Sigor@sysoev.ru nxt_eventport_poll, 80*12Sigor@sysoev.ru 81*12Sigor@sysoev.ru &nxt_unix_event_conn_io, 82*12Sigor@sysoev.ru 83*12Sigor@sysoev.ru NXT_NO_FILE_EVENTS, 84*12Sigor@sysoev.ru NXT_NO_SIGNAL_EVENTS, 85*12Sigor@sysoev.ru }; 86*12Sigor@sysoev.ru 87*12Sigor@sysoev.ru 88*12Sigor@sysoev.ru static nxt_int_t 89*12Sigor@sysoev.ru nxt_eventport_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, 90*12Sigor@sysoev.ru nxt_uint_t mevents) 91*12Sigor@sysoev.ru { 92*12Sigor@sysoev.ru nxt_eventport_change_t *changes; 93*12Sigor@sysoev.ru 94*12Sigor@sysoev.ru engine->u.eventport.fd = -1; 95*12Sigor@sysoev.ru engine->u.eventport.mchanges = mchanges; 96*12Sigor@sysoev.ru engine->u.eventport.mevents = mevents; 97*12Sigor@sysoev.ru 98*12Sigor@sysoev.ru changes = nxt_malloc(sizeof(nxt_eventport_change_t) * mchanges); 99*12Sigor@sysoev.ru if (changes == NULL) { 100*12Sigor@sysoev.ru goto fail; 101*12Sigor@sysoev.ru } 102*12Sigor@sysoev.ru 103*12Sigor@sysoev.ru engine->u.eventport.changes = changes; 104*12Sigor@sysoev.ru 105*12Sigor@sysoev.ru engine->u.eventport.events = nxt_malloc(sizeof(port_event_t) * mevents); 106*12Sigor@sysoev.ru if (engine->u.eventport.events == NULL) { 107*12Sigor@sysoev.ru goto fail; 108*12Sigor@sysoev.ru } 109*12Sigor@sysoev.ru 110*12Sigor@sysoev.ru engine->u.eventport.fd = port_create(); 111*12Sigor@sysoev.ru if (engine->u.eventport.fd == -1) { 112*12Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, "port_create() failed %E", 113*12Sigor@sysoev.ru nxt_errno); 114*12Sigor@sysoev.ru goto fail; 115*12Sigor@sysoev.ru } 116*12Sigor@sysoev.ru 117*12Sigor@sysoev.ru nxt_debug(&engine->task, "port_create(): %d", engine->u.eventport.fd); 118*12Sigor@sysoev.ru 119*12Sigor@sysoev.ru if (engine->signals != NULL) { 120*12Sigor@sysoev.ru engine->u.eventport.signal_handler = engine->signals->handler; 121*12Sigor@sysoev.ru } 122*12Sigor@sysoev.ru 123*12Sigor@sysoev.ru return NXT_OK; 124*12Sigor@sysoev.ru 125*12Sigor@sysoev.ru fail: 126*12Sigor@sysoev.ru 127*12Sigor@sysoev.ru nxt_eventport_free(engine); 128*12Sigor@sysoev.ru 129*12Sigor@sysoev.ru return NXT_ERROR; 130*12Sigor@sysoev.ru } 131*12Sigor@sysoev.ru 132*12Sigor@sysoev.ru 133*12Sigor@sysoev.ru static void 134*12Sigor@sysoev.ru nxt_eventport_free(nxt_event_engine_t *engine) 135*12Sigor@sysoev.ru { 136*12Sigor@sysoev.ru int port; 137*12Sigor@sysoev.ru 138*12Sigor@sysoev.ru port = engine->u.eventport.fd; 139*12Sigor@sysoev.ru 140*12Sigor@sysoev.ru nxt_debug(&engine->task, "eventport %d free", port); 141*12Sigor@sysoev.ru 142*12Sigor@sysoev.ru if (port != -1 && close(port) != 0) { 143*12Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, "eventport close(%d) failed %E", 144*12Sigor@sysoev.ru port, nxt_errno); 145*12Sigor@sysoev.ru } 146*12Sigor@sysoev.ru 147*12Sigor@sysoev.ru nxt_free(engine->u.eventport.events); 148*12Sigor@sysoev.ru 149*12Sigor@sysoev.ru nxt_memzero(&engine->u.eventport, sizeof(nxt_eventport_engine_t)); 150*12Sigor@sysoev.ru } 151*12Sigor@sysoev.ru 152*12Sigor@sysoev.ru 153*12Sigor@sysoev.ru static void 154*12Sigor@sysoev.ru nxt_eventport_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 155*12Sigor@sysoev.ru { 156*12Sigor@sysoev.ru ev->read = NXT_EVENT_ACTIVE; 157*12Sigor@sysoev.ru ev->write = NXT_EVENT_ACTIVE; 158*12Sigor@sysoev.ru 159*12Sigor@sysoev.ru nxt_eventport_enable_event(engine, ev, POLLIN | POLLOUT); 160*12Sigor@sysoev.ru } 161*12Sigor@sysoev.ru 162*12Sigor@sysoev.ru 163*12Sigor@sysoev.ru static void 164*12Sigor@sysoev.ru nxt_eventport_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 165*12Sigor@sysoev.ru { 166*12Sigor@sysoev.ru if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) { 167*12Sigor@sysoev.ru 168*12Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 169*12Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 170*12Sigor@sysoev.ru 171*12Sigor@sysoev.ru nxt_eventport_disable_event(engine, ev); 172*12Sigor@sysoev.ru } 173*12Sigor@sysoev.ru } 174*12Sigor@sysoev.ru 175*12Sigor@sysoev.ru 176*12Sigor@sysoev.ru /* 177*12Sigor@sysoev.ru * port_dissociate(3): 178*12Sigor@sysoev.ru * 179*12Sigor@sysoev.ru * The association is removed if the owner of the association closes the port. 180*12Sigor@sysoev.ru */ 181*12Sigor@sysoev.ru 182*12Sigor@sysoev.ru static nxt_bool_t 183*12Sigor@sysoev.ru nxt_eventport_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 184*12Sigor@sysoev.ru { 185*12Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 186*12Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 187*12Sigor@sysoev.ru 188*12Sigor@sysoev.ru return ev->changing; 189*12Sigor@sysoev.ru } 190*12Sigor@sysoev.ru 191*12Sigor@sysoev.ru 192*12Sigor@sysoev.ru static void 193*12Sigor@sysoev.ru nxt_eventport_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 194*12Sigor@sysoev.ru { 195*12Sigor@sysoev.ru nxt_uint_t events; 196*12Sigor@sysoev.ru 197*12Sigor@sysoev.ru if (ev->read != NXT_EVENT_BLOCKED) { 198*12Sigor@sysoev.ru events = (ev->write == NXT_EVENT_INACTIVE) ? POLLIN 199*12Sigor@sysoev.ru : (POLLIN | POLLOUT); 200*12Sigor@sysoev.ru nxt_eventport_enable_event(engine, ev, events); 201*12Sigor@sysoev.ru } 202*12Sigor@sysoev.ru 203*12Sigor@sysoev.ru ev->read = NXT_EVENT_ACTIVE; 204*12Sigor@sysoev.ru } 205*12Sigor@sysoev.ru 206*12Sigor@sysoev.ru 207*12Sigor@sysoev.ru static void 208*12Sigor@sysoev.ru nxt_eventport_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 209*12Sigor@sysoev.ru { 210*12Sigor@sysoev.ru nxt_uint_t events; 211*12Sigor@sysoev.ru 212*12Sigor@sysoev.ru if (ev->write != NXT_EVENT_BLOCKED) { 213*12Sigor@sysoev.ru events = (ev->read == NXT_EVENT_INACTIVE) ? POLLOUT 214*12Sigor@sysoev.ru : (POLLIN | POLLOUT); 215*12Sigor@sysoev.ru nxt_eventport_enable_event(engine, ev, events); 216*12Sigor@sysoev.ru } 217*12Sigor@sysoev.ru 218*12Sigor@sysoev.ru ev->write = NXT_EVENT_ACTIVE; 219*12Sigor@sysoev.ru } 220*12Sigor@sysoev.ru 221*12Sigor@sysoev.ru 222*12Sigor@sysoev.ru /* 223*12Sigor@sysoev.ru * eventport changes are batched to improve instruction and data 224*12Sigor@sysoev.ru * cache locality of several port_associate() and port_dissociate() 225*12Sigor@sysoev.ru * calls followed by port_getn() call. 226*12Sigor@sysoev.ru */ 227*12Sigor@sysoev.ru 228*12Sigor@sysoev.ru static void 229*12Sigor@sysoev.ru nxt_eventport_enable_event(nxt_event_engine_t *engine, nxt_fd_event_t *ev, 230*12Sigor@sysoev.ru nxt_uint_t events) 231*12Sigor@sysoev.ru { 232*12Sigor@sysoev.ru nxt_eventport_change_t *change; 233*12Sigor@sysoev.ru 234*12Sigor@sysoev.ru nxt_debug(ev->task, "port %d set event: fd:%d ev:%04XD u:%p", 235*12Sigor@sysoev.ru engine->u.eventport.fd, ev->fd, events, ev); 236*12Sigor@sysoev.ru 237*12Sigor@sysoev.ru if (engine->u.eventport.nchanges >= engine->u.eventport.mchanges) { 238*12Sigor@sysoev.ru (void) nxt_eventport_commit_changes(engine); 239*12Sigor@sysoev.ru } 240*12Sigor@sysoev.ru 241*12Sigor@sysoev.ru ev->changing = 1; 242*12Sigor@sysoev.ru 243*12Sigor@sysoev.ru change = &engine->u.eventport.changes[engine->u.eventport.nchanges++]; 244*12Sigor@sysoev.ru change->events = events; 245*12Sigor@sysoev.ru change->event = ev; 246*12Sigor@sysoev.ru } 247*12Sigor@sysoev.ru 248*12Sigor@sysoev.ru 249*12Sigor@sysoev.ru static void 250*12Sigor@sysoev.ru nxt_eventport_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 251*12Sigor@sysoev.ru { 252*12Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 253*12Sigor@sysoev.ru 254*12Sigor@sysoev.ru if (ev->write == NXT_EVENT_INACTIVE) { 255*12Sigor@sysoev.ru nxt_eventport_disable_event(engine, ev); 256*12Sigor@sysoev.ru 257*12Sigor@sysoev.ru } else { 258*12Sigor@sysoev.ru nxt_eventport_enable_event(engine, ev, POLLOUT); 259*12Sigor@sysoev.ru } 260*12Sigor@sysoev.ru } 261*12Sigor@sysoev.ru 262*12Sigor@sysoev.ru 263*12Sigor@sysoev.ru static void 264*12Sigor@sysoev.ru nxt_eventport_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 265*12Sigor@sysoev.ru { 266*12Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 267*12Sigor@sysoev.ru 268*12Sigor@sysoev.ru if (ev->read == NXT_EVENT_INACTIVE) { 269*12Sigor@sysoev.ru nxt_eventport_disable_event(engine, ev); 270*12Sigor@sysoev.ru 271*12Sigor@sysoev.ru } else { 272*12Sigor@sysoev.ru nxt_eventport_enable_event(engine, ev, POLLIN); 273*12Sigor@sysoev.ru } 274*12Sigor@sysoev.ru } 275*12Sigor@sysoev.ru 276*12Sigor@sysoev.ru 277*12Sigor@sysoev.ru static void 278*12Sigor@sysoev.ru nxt_eventport_disable_event(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 279*12Sigor@sysoev.ru { 280*12Sigor@sysoev.ru nxt_eventport_change_t *change; 281*12Sigor@sysoev.ru 282*12Sigor@sysoev.ru nxt_debug(ev->task, "port %d disable event : fd:%d", 283*12Sigor@sysoev.ru engine->u.eventport.fd, ev->fd); 284*12Sigor@sysoev.ru 285*12Sigor@sysoev.ru if (engine->u.eventport.nchanges >= engine->u.eventport.mchanges) { 286*12Sigor@sysoev.ru (void) nxt_eventport_commit_changes(engine); 287*12Sigor@sysoev.ru } 288*12Sigor@sysoev.ru 289*12Sigor@sysoev.ru ev->changing = 1; 290*12Sigor@sysoev.ru 291*12Sigor@sysoev.ru change = &engine->u.eventport.changes[engine->u.eventport.nchanges++]; 292*12Sigor@sysoev.ru change->events = 0; 293*12Sigor@sysoev.ru change->event = ev; 294*12Sigor@sysoev.ru } 295*12Sigor@sysoev.ru 296*12Sigor@sysoev.ru 297*12Sigor@sysoev.ru static nxt_int_t 298*12Sigor@sysoev.ru nxt_eventport_commit_changes(nxt_event_engine_t *engine) 299*12Sigor@sysoev.ru { 300*12Sigor@sysoev.ru int ret, port; 301*12Sigor@sysoev.ru nxt_int_t retval; 302*12Sigor@sysoev.ru nxt_fd_event_t *ev; 303*12Sigor@sysoev.ru nxt_eventport_change_t *change, *end; 304*12Sigor@sysoev.ru 305*12Sigor@sysoev.ru port = engine->u.eventport.fd; 306*12Sigor@sysoev.ru 307*12Sigor@sysoev.ru nxt_debug(&engine->task, "eventport %d changes:%ui", 308*12Sigor@sysoev.ru port, engine->u.eventport.nchanges); 309*12Sigor@sysoev.ru 310*12Sigor@sysoev.ru retval = NXT_OK; 311*12Sigor@sysoev.ru change = engine->u.eventport.changes; 312*12Sigor@sysoev.ru end = change + engine->u.eventport.nchanges; 313*12Sigor@sysoev.ru 314*12Sigor@sysoev.ru do { 315*12Sigor@sysoev.ru ev = change->event; 316*12Sigor@sysoev.ru ev->changing = 0; 317*12Sigor@sysoev.ru 318*12Sigor@sysoev.ru if (change->events != 0) { 319*12Sigor@sysoev.ru nxt_debug(ev->task, "port_associate(%d): fd:%d ev:%04XD u:%p", 320*12Sigor@sysoev.ru port, ev->fd, change->events, ev); 321*12Sigor@sysoev.ru 322*12Sigor@sysoev.ru ret = port_associate(port, PORT_SOURCE_FD, 323*12Sigor@sysoev.ru ev->fd, change->events, ev); 324*12Sigor@sysoev.ru 325*12Sigor@sysoev.ru if (nxt_fast_path(ret == 0)) { 326*12Sigor@sysoev.ru goto next; 327*12Sigor@sysoev.ru } 328*12Sigor@sysoev.ru 329*12Sigor@sysoev.ru nxt_log(ev->task, NXT_LOG_CRIT, 330*12Sigor@sysoev.ru "port_associate(%d, %d, %d, %04XD) failed %E", 331*12Sigor@sysoev.ru port, PORT_SOURCE_FD, ev->fd, change->events, nxt_errno); 332*12Sigor@sysoev.ru 333*12Sigor@sysoev.ru } else { 334*12Sigor@sysoev.ru nxt_debug(ev->task, "port_dissociate(%d): fd:%d", port, ev->fd); 335*12Sigor@sysoev.ru 336*12Sigor@sysoev.ru ret = port_dissociate(port, PORT_SOURCE_FD, ev->fd); 337*12Sigor@sysoev.ru 338*12Sigor@sysoev.ru if (nxt_fast_path(ret == 0)) { 339*12Sigor@sysoev.ru goto next; 340*12Sigor@sysoev.ru } 341*12Sigor@sysoev.ru 342*12Sigor@sysoev.ru nxt_log(ev->task, NXT_LOG_CRIT, 343*12Sigor@sysoev.ru "port_dissociate(%d, %d, %d) failed %E", 344*12Sigor@sysoev.ru port, PORT_SOURCE_FD, ev->fd, nxt_errno); 345*12Sigor@sysoev.ru } 346*12Sigor@sysoev.ru 347*12Sigor@sysoev.ru nxt_work_queue_add(&engine->fast_work_queue, 348*12Sigor@sysoev.ru nxt_eventport_error_handler, 349*12Sigor@sysoev.ru ev->task, ev, ev->data); 350*12Sigor@sysoev.ru 351*12Sigor@sysoev.ru retval = NXT_ERROR; 352*12Sigor@sysoev.ru 353*12Sigor@sysoev.ru next: 354*12Sigor@sysoev.ru 355*12Sigor@sysoev.ru change++; 356*12Sigor@sysoev.ru 357*12Sigor@sysoev.ru } while (change < end); 358*12Sigor@sysoev.ru 359*12Sigor@sysoev.ru engine->u.eventport.nchanges = 0; 360*12Sigor@sysoev.ru 361*12Sigor@sysoev.ru return retval; 362*12Sigor@sysoev.ru } 363*12Sigor@sysoev.ru 364*12Sigor@sysoev.ru 365*12Sigor@sysoev.ru static void 366*12Sigor@sysoev.ru nxt_eventport_error_handler(nxt_task_t *task, void *obj, void *data) 367*12Sigor@sysoev.ru { 368*12Sigor@sysoev.ru nxt_fd_event_t *ev; 369*12Sigor@sysoev.ru 370*12Sigor@sysoev.ru ev = obj; 371*12Sigor@sysoev.ru 372*12Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 373*12Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 374*12Sigor@sysoev.ru 375*12Sigor@sysoev.ru ev->error_handler(task, ev, data); 376*12Sigor@sysoev.ru } 377*12Sigor@sysoev.ru 378*12Sigor@sysoev.ru 379*12Sigor@sysoev.ru static void 380*12Sigor@sysoev.ru nxt_eventport_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 381*12Sigor@sysoev.ru { 382*12Sigor@sysoev.ru if (ev->read != NXT_EVENT_INACTIVE) { 383*12Sigor@sysoev.ru ev->read = NXT_EVENT_BLOCKED; 384*12Sigor@sysoev.ru } 385*12Sigor@sysoev.ru } 386*12Sigor@sysoev.ru 387*12Sigor@sysoev.ru 388*12Sigor@sysoev.ru static void 389*12Sigor@sysoev.ru nxt_eventport_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 390*12Sigor@sysoev.ru { 391*12Sigor@sysoev.ru if (ev->write != NXT_EVENT_INACTIVE) { 392*12Sigor@sysoev.ru ev->write = NXT_EVENT_BLOCKED; 393*12Sigor@sysoev.ru } 394*12Sigor@sysoev.ru } 395*12Sigor@sysoev.ru 396*12Sigor@sysoev.ru 397*12Sigor@sysoev.ru static void 398*12Sigor@sysoev.ru nxt_eventport_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 399*12Sigor@sysoev.ru { 400*12Sigor@sysoev.ru if (ev->read == NXT_EVENT_INACTIVE) { 401*12Sigor@sysoev.ru ev->read = NXT_EVENT_ACTIVE; 402*12Sigor@sysoev.ru 403*12Sigor@sysoev.ru nxt_eventport_enable_event(engine, ev, POLLIN); 404*12Sigor@sysoev.ru } 405*12Sigor@sysoev.ru } 406*12Sigor@sysoev.ru 407*12Sigor@sysoev.ru 408*12Sigor@sysoev.ru static void 409*12Sigor@sysoev.ru nxt_eventport_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 410*12Sigor@sysoev.ru { 411*12Sigor@sysoev.ru if (ev->write == NXT_EVENT_INACTIVE) { 412*12Sigor@sysoev.ru ev->write = NXT_EVENT_ACTIVE; 413*12Sigor@sysoev.ru 414*12Sigor@sysoev.ru nxt_eventport_enable_event(engine, ev, POLLOUT); 415*12Sigor@sysoev.ru } 416*12Sigor@sysoev.ru } 417*12Sigor@sysoev.ru 418*12Sigor@sysoev.ru 419*12Sigor@sysoev.ru static void 420*12Sigor@sysoev.ru nxt_eventport_enable_accept(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 421*12Sigor@sysoev.ru { 422*12Sigor@sysoev.ru ev->read = NXT_EVENT_LEVEL; 423*12Sigor@sysoev.ru 424*12Sigor@sysoev.ru nxt_eventport_enable_event(engine, ev, POLLIN); 425*12Sigor@sysoev.ru } 426*12Sigor@sysoev.ru 427*12Sigor@sysoev.ru 428*12Sigor@sysoev.ru static nxt_int_t 429*12Sigor@sysoev.ru nxt_eventport_enable_post(nxt_event_engine_t *engine, 430*12Sigor@sysoev.ru nxt_work_handler_t handler) 431*12Sigor@sysoev.ru { 432*12Sigor@sysoev.ru engine->u.eventport.post_handler = handler; 433*12Sigor@sysoev.ru 434*12Sigor@sysoev.ru return NXT_OK; 435*12Sigor@sysoev.ru } 436*12Sigor@sysoev.ru 437*12Sigor@sysoev.ru 438*12Sigor@sysoev.ru static void 439*12Sigor@sysoev.ru nxt_eventport_signal(nxt_event_engine_t *engine, nxt_uint_t signo) 440*12Sigor@sysoev.ru { 441*12Sigor@sysoev.ru int port; 442*12Sigor@sysoev.ru 443*12Sigor@sysoev.ru port = engine->u.eventport.fd; 444*12Sigor@sysoev.ru 445*12Sigor@sysoev.ru nxt_debug(&engine->task, "port_send(%d, %ui)", port, signo); 446*12Sigor@sysoev.ru 447*12Sigor@sysoev.ru if (port_send(port, signo, NULL) != 0) { 448*12Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, "port_send(%d) failed %E", 449*12Sigor@sysoev.ru port, nxt_errno); 450*12Sigor@sysoev.ru } 451*12Sigor@sysoev.ru } 452*12Sigor@sysoev.ru 453*12Sigor@sysoev.ru 454*12Sigor@sysoev.ru static void 455*12Sigor@sysoev.ru nxt_eventport_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) 456*12Sigor@sysoev.ru { 457*12Sigor@sysoev.ru int n, events, signo; 458*12Sigor@sysoev.ru uint_t nevents; 459*12Sigor@sysoev.ru nxt_err_t err; 460*12Sigor@sysoev.ru nxt_uint_t i, level; 461*12Sigor@sysoev.ru timespec_t ts, *tp; 462*12Sigor@sysoev.ru port_event_t *event; 463*12Sigor@sysoev.ru nxt_fd_event_t *ev; 464*12Sigor@sysoev.ru nxt_work_handler_t handler; 465*12Sigor@sysoev.ru 466*12Sigor@sysoev.ru if (engine->u.eventport.nchanges != 0) { 467*12Sigor@sysoev.ru if (nxt_eventport_commit_changes(engine) != NXT_OK) { 468*12Sigor@sysoev.ru /* Error handlers have been enqueued on failure. */ 469*12Sigor@sysoev.ru timeout = 0; 470*12Sigor@sysoev.ru } 471*12Sigor@sysoev.ru } 472*12Sigor@sysoev.ru 473*12Sigor@sysoev.ru if (timeout == NXT_INFINITE_MSEC) { 474*12Sigor@sysoev.ru tp = NULL; 475*12Sigor@sysoev.ru 476*12Sigor@sysoev.ru } else { 477*12Sigor@sysoev.ru ts.tv_sec = timeout / 1000; 478*12Sigor@sysoev.ru ts.tv_nsec = (timeout % 1000) * 1000000; 479*12Sigor@sysoev.ru tp = &ts; 480*12Sigor@sysoev.ru } 481*12Sigor@sysoev.ru 482*12Sigor@sysoev.ru nxt_debug(&engine->task, "port_getn(%d) timeout: %M", 483*12Sigor@sysoev.ru engine->u.eventport.fd, timeout); 484*12Sigor@sysoev.ru 485*12Sigor@sysoev.ru /* 486*12Sigor@sysoev.ru * A trap for possible error when Solaris does not update nevents 487*12Sigor@sysoev.ru * if ETIME or EINTR is returned. This issue will be logged as 488*12Sigor@sysoev.ru * "unexpected port_getn() event". 489*12Sigor@sysoev.ru * 490*12Sigor@sysoev.ru * The details are in OpenSolaris mailing list thread "port_getn() 491*12Sigor@sysoev.ru * and timeouts - is this a bug or an undocumented feature?" 492*12Sigor@sysoev.ru */ 493*12Sigor@sysoev.ru event = &engine->u.eventport.events[0]; 494*12Sigor@sysoev.ru event->portev_events = -1; /* invalid port events */ 495*12Sigor@sysoev.ru event->portev_source = -1; /* invalid port source */ 496*12Sigor@sysoev.ru event->portev_object = -1; 497*12Sigor@sysoev.ru event->portev_user = (void *) -1; 498*12Sigor@sysoev.ru 499*12Sigor@sysoev.ru nevents = 1; 500*12Sigor@sysoev.ru n = port_getn(engine->u.eventport.fd, engine->u.eventport.events, 501*12Sigor@sysoev.ru engine->u.eventport.mevents, &nevents, tp); 502*12Sigor@sysoev.ru 503*12Sigor@sysoev.ru /* 504*12Sigor@sysoev.ru * 32-bit port_getn() on Solaris 10 x86 returns large negative 505*12Sigor@sysoev.ru * values instead of 0 when returning immediately. 506*12Sigor@sysoev.ru */ 507*12Sigor@sysoev.ru err = (n < 0) ? nxt_errno : 0; 508*12Sigor@sysoev.ru 509*12Sigor@sysoev.ru nxt_thread_time_update(engine->task.thread); 510*12Sigor@sysoev.ru 511*12Sigor@sysoev.ru if (n == -1) { 512*12Sigor@sysoev.ru if (err == NXT_ETIME || err == NXT_EINTR) { 513*12Sigor@sysoev.ru if (nevents != 0) { 514*12Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, 515*12Sigor@sysoev.ru "port_getn(%d) failed %E, events:%ud", 516*12Sigor@sysoev.ru engine->u.eventport.fd, err, nevents); 517*12Sigor@sysoev.ru } 518*12Sigor@sysoev.ru } 519*12Sigor@sysoev.ru 520*12Sigor@sysoev.ru if (err != NXT_ETIME) { 521*12Sigor@sysoev.ru level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_CRIT; 522*12Sigor@sysoev.ru 523*12Sigor@sysoev.ru nxt_log(&engine->task, level, "port_getn(%d) failed %E", 524*12Sigor@sysoev.ru engine->u.eventport.fd, err); 525*12Sigor@sysoev.ru 526*12Sigor@sysoev.ru if (err != NXT_EINTR) { 527*12Sigor@sysoev.ru return; 528*12Sigor@sysoev.ru } 529*12Sigor@sysoev.ru } 530*12Sigor@sysoev.ru } 531*12Sigor@sysoev.ru 532*12Sigor@sysoev.ru nxt_debug(&engine->task, "port_getn(%d) events: %d", 533*12Sigor@sysoev.ru engine->u.eventport.fd, nevents); 534*12Sigor@sysoev.ru 535*12Sigor@sysoev.ru for (i = 0; i < nevents; i++) { 536*12Sigor@sysoev.ru event = &engine->u.eventport.events[i]; 537*12Sigor@sysoev.ru 538*12Sigor@sysoev.ru switch (event->portev_source) { 539*12Sigor@sysoev.ru 540*12Sigor@sysoev.ru case PORT_SOURCE_FD: 541*12Sigor@sysoev.ru ev = event->portev_user; 542*12Sigor@sysoev.ru events = event->portev_events; 543*12Sigor@sysoev.ru 544*12Sigor@sysoev.ru nxt_debug(ev->task, "eventport: fd:%d ev:%04Xd u:%p rd:%d wr:%d", 545*12Sigor@sysoev.ru event->portev_object, events, ev, ev->read, ev->write); 546*12Sigor@sysoev.ru 547*12Sigor@sysoev.ru if (nxt_slow_path(events & (POLLERR | POLLHUP | POLLNVAL)) != 0) { 548*12Sigor@sysoev.ru nxt_log(ev->task, NXT_LOG_CRIT, 549*12Sigor@sysoev.ru "port_getn(%d) error fd:%d events:%04Xud", 550*12Sigor@sysoev.ru engine->u.eventport.fd, ev->fd, events); 551*12Sigor@sysoev.ru 552*12Sigor@sysoev.ru nxt_work_queue_add(&engine->fast_work_queue, 553*12Sigor@sysoev.ru nxt_eventport_error_handler, 554*12Sigor@sysoev.ru ev->task, ev, ev->data); 555*12Sigor@sysoev.ru continue; 556*12Sigor@sysoev.ru } 557*12Sigor@sysoev.ru 558*12Sigor@sysoev.ru if (events & POLLIN) { 559*12Sigor@sysoev.ru ev->read_ready = 1; 560*12Sigor@sysoev.ru 561*12Sigor@sysoev.ru if (ev->read != NXT_EVENT_BLOCKED) { 562*12Sigor@sysoev.ru nxt_work_queue_add(ev->read_work_queue, ev->read_handler, 563*12Sigor@sysoev.ru ev->task, ev, ev->data); 564*12Sigor@sysoev.ru 565*12Sigor@sysoev.ru } 566*12Sigor@sysoev.ru 567*12Sigor@sysoev.ru if (ev->read != NXT_EVENT_LEVEL) { 568*12Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 569*12Sigor@sysoev.ru } 570*12Sigor@sysoev.ru } 571*12Sigor@sysoev.ru 572*12Sigor@sysoev.ru if (events & POLLOUT) { 573*12Sigor@sysoev.ru ev->write_ready = 1; 574*12Sigor@sysoev.ru 575*12Sigor@sysoev.ru if (ev->write != NXT_EVENT_BLOCKED) { 576*12Sigor@sysoev.ru nxt_work_queue_add(ev->write_work_queue, ev->write_handler, 577*12Sigor@sysoev.ru ev->task, ev, ev->data); 578*12Sigor@sysoev.ru } 579*12Sigor@sysoev.ru 580*12Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 581*12Sigor@sysoev.ru } 582*12Sigor@sysoev.ru 583*12Sigor@sysoev.ru /* 584*12Sigor@sysoev.ru * Reactivate counterpart direction, because the 585*12Sigor@sysoev.ru * eventport is oneshot notification facility. 586*12Sigor@sysoev.ru */ 587*12Sigor@sysoev.ru events = (ev->read == NXT_EVENT_INACTIVE) ? 0 : POLLIN; 588*12Sigor@sysoev.ru events |= (ev->write == NXT_EVENT_INACTIVE) ? 0 : POLLOUT; 589*12Sigor@sysoev.ru 590*12Sigor@sysoev.ru if (events != 0) { 591*12Sigor@sysoev.ru nxt_eventport_enable_event(engine, ev, events); 592*12Sigor@sysoev.ru } 593*12Sigor@sysoev.ru 594*12Sigor@sysoev.ru break; 595*12Sigor@sysoev.ru 596*12Sigor@sysoev.ru case PORT_SOURCE_USER: 597*12Sigor@sysoev.ru nxt_debug(&engine->task, "eventport: user ev:%d u:%p", 598*12Sigor@sysoev.ru event->portev_events, event->portev_user); 599*12Sigor@sysoev.ru 600*12Sigor@sysoev.ru signo = event->portev_events; 601*12Sigor@sysoev.ru 602*12Sigor@sysoev.ru handler = (signo == 0) ? engine->u.eventport.post_handler 603*12Sigor@sysoev.ru : engine->u.eventport.signal_handler; 604*12Sigor@sysoev.ru 605*12Sigor@sysoev.ru nxt_work_queue_add(&engine->fast_work_queue, handler, 606*12Sigor@sysoev.ru &engine->task, (void *) (uintptr_t) signo, NULL); 607*12Sigor@sysoev.ru 608*12Sigor@sysoev.ru break; 609*12Sigor@sysoev.ru 610*12Sigor@sysoev.ru default: 611*12Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, 612*12Sigor@sysoev.ru "unexpected port_getn(%d) event: ev:%d src:%d obj:%p u:%p", 613*12Sigor@sysoev.ru engine->u.eventport.fd, event->portev_events, 614*12Sigor@sysoev.ru event->portev_source, event->portev_object, 615*12Sigor@sysoev.ru event->portev_user); 616*12Sigor@sysoev.ru } 617*12Sigor@sysoev.ru } 618*12Sigor@sysoev.ru } 619