/* * Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. */ #include "opal_config.h" #include "opal/constants.h" /* protect common defines */ #undef PACKAGE_BUGREPORT #undef PACKAGE_NAME #undef PACKAGE_STRING #undef PACKAGE_TARNAME #undef PACKAGE_VERSION #include "libevent/config.h" #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #include #include #ifndef WIN32 #ifdef HAVE_UNISTD_H #include #endif #endif #include #include #include #include #include #include "opal/class/opal_object.h" #include "opal/threads/mutex.h" #include "opal/threads/threads.h" #include "opal/util/output.h" #include "opal/util/argv.h" #include "opal/util/fd.h" #include "opal/mca/base/mca_base_param.h" #include "libevent2013.h" #include "opal/mca/event/base/base.h" #include "libevent/event.h" #include "libevent/event-internal.h" #include "opal/mca/event/event.h" /* copied from event.c */ #if defined(_EVENT_HAVE_EVENT_PORTS) && _EVENT_HAVE_EVENT_PORTS extern const struct eventop evportops; #endif #if defined(_EVENT_HAVE_SELECT) && _EVENT_HAVE_SELECT extern const struct eventop selectops; #endif #if defined(_EVENT_HAVE_POLL) && _EVENT_HAVE_POLL extern const struct eventop pollops; #endif #if defined(_EVENT_HAVE_EPOLL) && _EVENT_HAVE_EPOLL extern const struct eventop epollops; #endif #if defined(_EVENT_HAVE_WORKING_KQUEUE) && _EVENT_HAVE_WORKING_KQUEUE extern const struct eventop kqops; #endif #if defined(_EVENT_HAVE_DEVPOLL) && _EVENT_HAVE_DEVPOLL extern const struct eventop devpollops; #endif #ifdef WIN32 extern const struct eventop win32ops; #endif /* Array of backends in order of preference. */ static const struct eventop *eventops[] = { #if defined(_EVENT_HAVE_EVENT_PORTS) && _EVENT_HAVE_EVENT_PORTS &evportops, #endif #if defined(_EVENT_HAVE_WORKING_KQUEUE) && _EVENT_HAVE_WORKING_KQUEUE &kqops, #endif #if defined(_EVENT_HAVE_EPOLL) && _EVENT_HAVE_EPOLL &epollops, #endif #if defined(_EVENT_HAVE_DEVPOLL) && _EVENT_HAVE_DEVPOLL &devpollops, #endif #if defined(_EVENT_HAVE_POLL) && _EVENT_HAVE_POLL &pollops, #endif #if defined(_EVENT_HAVE_SELECT) && _EVENT_HAVE_SELECT &selectops, #endif #ifdef WIN32 &win32ops, #endif NULL }; static struct event_config *config=NULL; static void update_event(int fd, short flags, void* arg) { opal_event_update_t up; /* read the event */ opal_fd_read(fd, sizeof(opal_event_update_t), &up); if (NULL == up.ev) { return; } if (OPAL_EVENT_ADD == up.op) { event_add(up.ev, 0); } else if (OPAL_EVENT_DEL == up.op) { event_del(up.ev); } return; } /* Public function -- not part of the module */ /* This includes (hopefully) a temporary change * to deal with cross-base sync. Specifically, * when an event in one base needs to release * a condition_wait in another base, we need * to "wakeup" the event base in the second base * so the condition_wait can be checked */ opal_event_base_t* opal_event_base_create(void) { struct event_base *base; opal_event_base_t *evbase; base = event_base_new_with_config(config); if (NULL == base) { /* there is no backend method that does what we want */ opal_output(0, "No event method available"); return NULL; } evbase = (opal_event_base_t*)malloc(sizeof(opal_event_base_t)); evbase->base = base; #ifndef __WINDOWS__ if (pipe(evbase->update_pipe) < 0) { opal_output(0, "Unable to open update pipe"); free(evbase); event_base_free(base); return NULL; } #else if (create_socketpair(AF_UNIX, SOCK_STREAM, 0, evbase->update_pipe) == -1) { opal_output(0, "Unable to open update socket"); free(evbase); event_base_free(base); return NULL; } #endif event_assign(&evbase->update_event, base, evbase->update_pipe[0], EV_READ | EV_PERSIST, update_event, NULL); event_add(&evbase->update_event, 0); return evbase; } void opal_event_base_finalize(opal_event_base_t *evbase) { /* delete the wakeup event */ event_del(&evbase->update_event); #ifndef __WINDOWS__ /* close the pipe */ close(evbase->update_pipe[0]); close(evbase->update_pipe[1]); #else /* close the socket */ closesocket(evbase->update_pipe[0]); closesocket(evbase->update_pipe[1]); #endif /* release the base */ event_base_free(evbase->base); /* free the storage */ free(evbase); } int opal_event_init(void) { char* event_module_include=NULL; char **modules=NULL, **includes=NULL; bool dumpit=false; int i, j; const struct eventop** _eventop = eventops; char available_eventops[1024] = "none"; char* help_msg = NULL; int position = 0; if (opal_output_get_verbosity(opal_event_base_output) > 4) { event_enable_debug_mode(); event_set_debug_output(true); dumpit = true; } #if OPAL_EVENT_HAVE_THREAD_SUPPORT /* turn on libevent thread safety */ evthread_use_pthreads (); #endif /* Retrieve the upper level specified event system, if any. * Default to select() on OS X and poll() everywhere else because * various parts of OMPI / ORTE use libevent with pty's. pty's * *only* work with select on OS X (tested on Tiger and Leopard); * we *know* that both select and poll works with pty's everywhere * else we care about (other mechansisms such as epoll *may* work * with pty's -- we have not tested comprehensively with newer * versions of Linux, etc.). So the safe thing to do is: * * - On OS X, default to using "select" only * - Everywhere else, default to using "poll" only (because poll * is more scalable than select) * * An upper layer may override this setting if it knows that pty's * won't be used with libevent. For example, we currently have * ompi_mpi_init() set to use "all" (to include epoll and friends) * so that the TCP BTL can be a bit more scalable -- because we * *know* that MPI apps don't use pty's with libevent. * Note that other tools explicitly *do* use pty's with libevent: * * - orted * - orterun (probably only if it launches locally) * - ...? */ while( NULL != (*_eventop) ) { opal_argv_append_nosize(&modules, (*_eventop)->name); if( 0 != position ) { position += snprintf( available_eventops + position, (size_t)(1024 - position), ", %s", (*_eventop)->name ); } else { position += snprintf( available_eventops + position, (size_t)(1024 - position), "%s", (*_eventop)->name ); } available_eventops[position] = '\0'; _eventop++; /* go to the next available eventop */ } asprintf( &help_msg, "Comma-delimited list of libevent subsystems " "to use (%s -- available on your platform)", available_eventops ); mca_base_param_reg_string_name("opal", "event_include", help_msg, false, false, #ifdef __APPLE__ "select", #else #ifdef __WINDOWS__ "win32", #else "poll", #endif #endif &event_module_include); if (dumpit) { opal_output(0, "event: available subsystems: %s", available_eventops); } free(help_msg); /* release the help message */ if (NULL == event_module_include) { /* Shouldn't happen, but... */ event_module_include = strdup("select"); } includes = opal_argv_split(event_module_include,','); free(event_module_include); /* get a configuration object */ config = event_config_new(); /* cycle thru the available subsystems */ for (i=0; NULL != modules[i]; i++) { /* if this module isn't included in the given ones, * then exclude it */ dumpit = true; for (j=0; NULL != includes[j]; j++) { if (0 == strcmp("all", includes[j]) || 0 == strcmp(modules[i], includes[j])) { dumpit = false; break; } } if (dumpit) { event_config_avoid_method(config, modules[i]); } } opal_argv_free(includes); opal_argv_free(modules); return OPAL_SUCCESS; } int opal_event_reinit(opal_event_base_t *evbase) { return event_reinit(evbase->base); } struct timeval *opal_event_base_init_common_timeout (opal_event_base_t *evbase, struct timeval *tv_in) { return (struct timeval*)event_base_init_common_timeout (evbase->base, tv_in); }