static void do_parent(int thefd) { struct timespec timeout = { 1, 0 }; char buf[500000]; struct kevent kev; int iter = 0, kq = kqueue(); if (-1 == (kq = kqueue())) { fprintf(stderr, "kqueue(): %s\n", strerror(errno)); exit(EXIT_FAILURE); } if (-1 == fcntl(thefd, F_SETFL, O_NONBLOCK)) { fprintf(stderr, "fcntl(): %s\n", strerror(errno)); exit(EXIT_FAILURE); } EV_SET(&kev, thefd, EVFILT_READ, EV_ADD, 0, 0, NULL); if (-1 == kevent(kq, &kev, 1, NULL, 0, NULL)) { fprintf(stderr, "%d: kevent(): %s\n", __LINE__, strerror(errno)); exit(EXIT_FAILURE); } for (;;) { switch (kevent(kq, NULL, 0, &kev, 1, &timeout)) { case -1: fprintf(stderr, "%d: kevent(): %s\n", __LINE__, strerror(errno)); exit(EXIT_FAILURE); case 0: fprintf(stderr, "After %d iterations, 4038866 still exists!\n", iter); exit(EXIT_FAILURE); case 1: break; default: fprintf(stderr, "kevent should only return -1, 0 or 1 for this case!\n"); exit(EXIT_FAILURE); } switch (kev.filter) { case EVFILT_READ: if (-1 == read(thefd, buf, sizeof(buf))) { fprintf(stderr, "read(): %s\n", strerror(errno)); exit(EXIT_FAILURE); } if (-1 == write(thefd, buf, sizeof(buf))) { fprintf(stderr, "%d: write(): %s\n", __LINE__, strerror(errno)); exit(EXIT_FAILURE); } EV_SET(&kev, thefd, EVFILT_WRITE, EV_ADD, 0, 0, NULL); if (-1 == kevent(kq, &kev, 1, NULL, 0, NULL)) { fprintf(stderr, "%d: kevent(): %s\n", __LINE__, strerror(errno)); exit(EXIT_FAILURE); } break; case EVFILT_WRITE: if (-1 == write(thefd, buf, 1)) { fprintf(stderr, "%d: write(): %s\n", __LINE__, strerror(errno)); exit(EXIT_FAILURE); } EV_SET(&kev, thefd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); if (-1 == kevent(kq, &kev, 1, NULL, 0, NULL)) { fprintf(stderr, "%d: kevent(): %s\n", __LINE__, strerror(errno)); exit(EXIT_FAILURE); } break; default: fprintf(stderr, "kevent filter isn't EVFILT_READ or EVFILT_WRITE!\n"); exit(EXIT_FAILURE); } iter++; } }
void uqueue_watch(uqueue *q, mplx3_endpoint *ep) { EV_SET(q->changes + q->changes_count, ep->sockfd, EVFILT_READ, EV_ADD|EV_CLEAR|EV_ENABLE, 0, 0, ep); q->changes_count++; }
void uqueue_filter_set(uqueue *q, mplx3_endpoint *ep) { EV_SET(q->changes + q->changes_count, ep->sockfd, ep->new_filter, EV_ADD|EV_ENABLE|EV_CLEAR, 0, 0, ep); q->changes_count++; }
static void kq_update_events(rb_fde_t *F, short filter, PF * handler) { PF *cur_handler; int kep_flags; switch (filter) { case EVFILT_READ: cur_handler = F->read_handler; break; case EVFILT_WRITE: cur_handler = F->write_handler; break; default: /* XXX bad! -- adrian */ return; break; } if((cur_handler == NULL && handler != NULL) || (cur_handler != NULL && handler == NULL)) { struct kevent *kep; kep = kqlst + kqoff; if(handler != NULL) { kep_flags = EV_ADD | EV_ONESHOT; } else { kep_flags = EV_DELETE; } EV_SET(kep, (uintptr_t)F->fd, filter, kep_flags, 0, 0, (void *)F); if(++kqoff == kqmax) { int ret, i; /* Add them one at a time, because there may be * already closed fds in it. The kernel will try * to report invalid fds in the output; if there * is no space, it silently stops processing the * array at that point. We cannot give output space * because that would also return events we cannot * process at this point. */ for(i = 0; i < kqoff; i++) { ret = kevent(kq, kqlst + i, 1, NULL, 0, &zero_timespec); /* jdc -- someone needs to do error checking... */ /* EBADF is normal here -- jilles */ if(ret == -1 && errno != EBADF) rb_lib_log("kq_update_events(): kevent(): %s", strerror(errno)); } kqoff = 0; } } }
int main(int argc, char **argv) { int option; char *configfile; int background; int mdns_no_rsp; int mdns_no_daap; int mdns_no_mpd; int loglevel; char *logdomains; char *logfile; char *ffid; char *pidfile; const char *gcry_version; sigset_t sigs; int sigfd; #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) struct kevent ke_sigs[4]; #endif int ret; struct option option_map[] = { { "ffid", 1, NULL, 'b' }, { "debug", 1, NULL, 'd' }, { "logdomains", 1, NULL, 'D' }, { "foreground", 0, NULL, 'f' }, { "config", 1, NULL, 'c' }, { "pidfile", 1, NULL, 'P' }, { "version", 0, NULL, 'v' }, { "mdns-no-rsp", 0, NULL, 512 }, { "mdns-no-daap", 0, NULL, 513 }, { NULL, 0, NULL, 0 } }; configfile = CONFFILE; pidfile = PIDFILE; loglevel = -1; logdomains = NULL; logfile = NULL; background = 1; ffid = NULL; mdns_no_rsp = 0; mdns_no_daap = 0; mdns_no_mpd = 1; // only announce if mpd protocol support is activated while ((option = getopt_long(argc, argv, "D:d:c:P:fb:v", option_map, NULL)) != -1) { switch (option) { case 512: mdns_no_rsp = 1; break; case 513: mdns_no_daap = 1; break; case 'b': ffid = optarg; break; case 'd': ret = safe_atoi32(optarg, &option); if (ret < 0) fprintf(stderr, "Error: loglevel must be an integer in '-d %s'\n", optarg); else loglevel = option; break; case 'D': logdomains = optarg; break; case 'f': background = 0; break; case 'c': configfile = optarg; break; case 'P': pidfile = optarg; break; case 'v': version(); return EXIT_SUCCESS; break; default: usage(argv[0]); return EXIT_FAILURE; break; } } ret = logger_init(NULL, NULL, (loglevel < 0) ? E_LOG : loglevel); if (ret != 0) { fprintf(stderr, "Could not initialize log facility\n"); return EXIT_FAILURE; } ret = conffile_load(configfile); if (ret != 0) { DPRINTF(E_FATAL, L_MAIN, "Config file errors; please fix your config\n"); logger_deinit(); return EXIT_FAILURE; } logger_deinit(); /* Reinit log facility with configfile values */ if (loglevel < 0) loglevel = cfg_getint(cfg_getsec(cfg, "general"), "loglevel"); logfile = cfg_getstr(cfg_getsec(cfg, "general"), "logfile"); ret = logger_init(logfile, logdomains, loglevel); if (ret != 0) { fprintf(stderr, "Could not reinitialize log facility with config file settings\n"); conffile_unload(); return EXIT_FAILURE; } /* Set up libevent logging callback */ event_set_log_callback(logger_libevent); DPRINTF(E_LOG, L_MAIN, "Forked Media Server Version %s taking off\n", VERSION); ret = av_lockmgr_register(ffmpeg_lockmgr); if (ret < 0) { DPRINTF(E_FATAL, L_MAIN, "Could not register ffmpeg lock manager callback\n"); ret = EXIT_FAILURE; goto ffmpeg_init_fail; } av_register_all(); avfilter_register_all(); #if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 13) avformat_network_init(); #endif av_log_set_callback(logger_ffmpeg); #ifdef LASTFM /* Initialize libcurl */ curl_global_init(CURL_GLOBAL_DEFAULT); #endif /* Initialize libgcrypt */ gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); gcry_version = gcry_check_version(GCRYPT_VERSION); if (!gcry_version) { DPRINTF(E_FATAL, L_MAIN, "libgcrypt version mismatch\n"); ret = EXIT_FAILURE; goto gcrypt_init_fail; } /* We aren't handling anything sensitive, so give up on secure * memory, which is a scarce system resource. */ gcry_control(GCRYCTL_DISABLE_SECMEM, 0); gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); DPRINTF(E_DBG, L_MAIN, "Initialized with gcrypt %s\n", gcry_version); /* Block signals for all threads except the main one */ sigemptyset(&sigs); sigaddset(&sigs, SIGINT); sigaddset(&sigs, SIGHUP); sigaddset(&sigs, SIGCHLD); sigaddset(&sigs, SIGTERM); sigaddset(&sigs, SIGPIPE); ret = pthread_sigmask(SIG_BLOCK, &sigs, NULL); if (ret != 0) { DPRINTF(E_LOG, L_MAIN, "Error setting signal set\n"); ret = EXIT_FAILURE; goto signal_block_fail; } /* Daemonize and drop privileges */ ret = daemonize(background, pidfile); if (ret < 0) { DPRINTF(E_LOG, L_MAIN, "Could not initialize server\n"); ret = EXIT_FAILURE; goto daemon_fail; } /* Initialize event base (after forking) */ evbase_main = event_base_new(); DPRINTF(E_LOG, L_MAIN, "mDNS init\n"); ret = mdns_init(); if (ret != 0) { DPRINTF(E_FATAL, L_MAIN, "mDNS init failed\n"); ret = EXIT_FAILURE; goto mdns_fail; } /* Initialize the database before starting */ DPRINTF(E_INFO, L_MAIN, "Initializing database\n"); ret = db_init(); if (ret < 0) { DPRINTF(E_FATAL, L_MAIN, "Database init failed\n"); ret = EXIT_FAILURE; goto db_fail; } /* Open a DB connection for the main thread */ ret = db_perthread_init(); if (ret < 0) { DPRINTF(E_FATAL, L_MAIN, "Could not perform perthread DB init for main\n"); ret = EXIT_FAILURE; goto db_fail; } /* Spawn worker thread */ ret = worker_init(); if (ret != 0) { DPRINTF(E_FATAL, L_MAIN, "Worker thread failed to start\n"); ret = EXIT_FAILURE; goto worker_fail; } /* Spawn cache thread */ ret = cache_init(); if (ret != 0) { DPRINTF(E_FATAL, L_MAIN, "Cache thread failed to start\n"); ret = EXIT_FAILURE; goto cache_fail; } /* Spawn file scanner thread */ ret = filescanner_init(); if (ret != 0) { DPRINTF(E_FATAL, L_MAIN, "File scanner thread failed to start\n"); ret = EXIT_FAILURE; goto filescanner_fail; } #ifdef HAVE_SPOTIFY_H /* Spawn Spotify thread */ ret = spotify_init(); if (ret < 0) { DPRINTF(E_INFO, L_MAIN, "Spotify thread not started\n");; } #endif /* Spawn player thread */ ret = player_init(); if (ret != 0) { DPRINTF(E_FATAL, L_MAIN, "Player thread failed to start\n"); ret = EXIT_FAILURE; goto player_fail; } /* Spawn HTTPd thread */ ret = httpd_init(); if (ret != 0) { DPRINTF(E_FATAL, L_MAIN, "HTTPd thread failed to start\n"); ret = EXIT_FAILURE; goto httpd_fail; } #ifdef MPD /* Spawn MPD thread */ ret = mpd_init(); if (ret != 0) { DPRINTF(E_FATAL, L_MAIN, "MPD thread failed to start\n"); ret = EXIT_FAILURE; goto mpd_fail; } mdns_no_mpd = 0; #endif /* Start Remote pairing service */ ret = remote_pairing_init(); if (ret != 0) { DPRINTF(E_FATAL, L_MAIN, "Remote pairing service failed to start\n"); ret = EXIT_FAILURE; goto remote_fail; } /* Register mDNS services */ ret = register_services(ffid, mdns_no_rsp, mdns_no_daap, mdns_no_mpd); if (ret < 0) { ret = EXIT_FAILURE; goto mdns_reg_fail; } #if defined(__linux__) /* Set up signal fd */ sigfd = signalfd(-1, &sigs, SFD_NONBLOCK | SFD_CLOEXEC); if (sigfd < 0) { DPRINTF(E_FATAL, L_MAIN, "Could not setup signalfd: %s\n", strerror(errno)); ret = EXIT_FAILURE; goto signalfd_fail; } sig_event = event_new(evbase_main, sigfd, EV_READ, signal_signalfd_cb, NULL); #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) sigfd = kqueue(); if (sigfd < 0) { DPRINTF(E_FATAL, L_MAIN, "Could not setup kqueue: %s\n", strerror(errno)); ret = EXIT_FAILURE; goto signalfd_fail; } EV_SET(&ke_sigs[0], SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); EV_SET(&ke_sigs[1], SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); EV_SET(&ke_sigs[2], SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); EV_SET(&ke_sigs[3], SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); ret = kevent(sigfd, ke_sigs, 4, NULL, 0, NULL); if (ret < 0) { DPRINTF(E_FATAL, L_MAIN, "Could not register signal events: %s\n", strerror(errno)); ret = EXIT_FAILURE; goto signalfd_fail; } sig_event = event_new(evbase_main, sigfd, EV_READ, signal_kqueue_cb, NULL); #endif if (!sig_event) { DPRINTF(E_FATAL, L_MAIN, "Could not create signal event\n"); ret = EXIT_FAILURE; goto sig_event_fail; } event_add(sig_event, NULL); /* Run the loop */ event_base_dispatch(evbase_main); DPRINTF(E_LOG, L_MAIN, "Stopping gracefully\n"); ret = EXIT_SUCCESS; /* * On a clean shutdown, bring mDNS down first to give a chance * to the clients to perform a clean shutdown on their end */ DPRINTF(E_LOG, L_MAIN, "mDNS deinit\n"); mdns_deinit(); sig_event_fail: signalfd_fail: mdns_reg_fail: DPRINTF(E_LOG, L_MAIN, "Remote pairing deinit\n"); remote_pairing_deinit(); remote_fail: #ifdef MPD DPRINTF(E_LOG, L_MAIN, "MPD deinit\n"); mpd_deinit(); mpd_fail: #endif DPRINTF(E_LOG, L_MAIN, "HTTPd deinit\n"); httpd_deinit(); httpd_fail: DPRINTF(E_LOG, L_MAIN, "Player deinit\n"); player_deinit(); player_fail: #ifdef HAVE_SPOTIFY_H DPRINTF(E_LOG, L_MAIN, "Spotify deinit\n"); spotify_deinit(); #endif DPRINTF(E_LOG, L_MAIN, "File scanner deinit\n"); filescanner_deinit(); filescanner_fail: DPRINTF(E_LOG, L_MAIN, "Cache deinit\n"); cache_deinit(); cache_fail: DPRINTF(E_LOG, L_MAIN, "Worker deinit\n"); worker_deinit(); worker_fail: DPRINTF(E_LOG, L_MAIN, "Database deinit\n"); db_perthread_deinit(); db_deinit(); db_fail: if (ret == EXIT_FAILURE) { DPRINTF(E_LOG, L_MAIN, "mDNS deinit\n"); mdns_deinit(); } mdns_fail: daemon_fail: if (background) { ret = seteuid(0); if (ret < 0) DPRINTF(E_LOG, L_MAIN, "seteuid() failed: %s\n", strerror(errno)); else { ret = unlink(pidfile); if (ret < 0) DPRINTF(E_LOG, L_MAIN, "Could not unlink PID file %s: %s\n", pidfile, strerror(errno)); } } signal_block_fail: gcrypt_init_fail: #ifdef LASTFM curl_global_cleanup(); #endif #if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 13) avformat_network_deinit(); #endif av_lockmgr_register(NULL); ffmpeg_init_fail: DPRINTF(E_LOG, L_MAIN, "Exiting.\n"); conffile_unload(); logger_deinit(); return ret; }
/* * Test read kevent on a socket pair: check to make sure endpoint 0 isn't * readable when we start, then write to endpoint 1 and confirm that endpoint * 0 is now readable. Drain the write, then check that it's not readable * again. Use non-blocking kqueue operations and socket operations. */ static void test_evfilt_read(int kq, int fd[2], const char *socktype) { struct timespec ts; struct kevent ke; ssize_t len; char ch; int i; EV_SET(&ke, fd[0], EVFILT_READ, EV_ADD, 0, 0, NULL); if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) fail(errno, "kevent", socktype, "EVFILT_READ, EV_ADD"); OK("EVFILT_READ, EV_ADD"); /* * Confirm not readable to begin with, no I/O yet. */ ts.tv_sec = 0; ts.tv_nsec = 0; i = kevent(kq, NULL, 0, &ke, 1, &ts); if (i == -1) fail(errno, "kevent", socktype, "EVFILT_READ"); OK("EVFILT_READ"); if (i != 0) fail_assertion("kevent", socktype, "EVFILT_READ", "empty socket unreadable"); OK("empty socket unreadable"); /* * Write a byte to one end. */ ch = 'a'; len = write(fd[1], &ch, sizeof(ch)); if (len == -1) fail(errno, "write", socktype, NULL); OK("write one byte"); if (len != sizeof(ch)) fail_assertion("write", socktype, NULL, "write length"); OK("write one byte length"); /* * Other end should now be readable. */ ts.tv_sec = 0; ts.tv_nsec = 0; i = kevent(kq, NULL, 0, &ke, 1, &ts); if (i == -1) fail(errno, "kevent", socktype, "EVFILT_READ"); OK("EVFILT_READ"); if (i != 1) fail_assertion("kevent", socktype, "EVFILT_READ", "non-empty socket unreadable"); OK("non-empty socket unreadable"); /* * Read a byte to clear the readable state. */ len = read(fd[0], &ch, sizeof(ch)); if (len == -1) fail(errno, "read", socktype, NULL); OK("read one byte"); if (len != sizeof(ch)) fail_assertion("read", socktype, NULL, "read length"); OK("read one byte length"); /* * Now re-check for readability. */ ts.tv_sec = 0; ts.tv_nsec = 0; i = kevent(kq, NULL, 0, &ke, 1, &ts); if (i == -1) fail(errno, "kevent", socktype, "EVFILT_READ"); OK("EVFILT_READ"); if (i != 0) fail_assertion("kevent", socktype, "EVFILT_READ", "empty socket unreadable"); OK("empty socket unreadable"); EV_SET(&ke, fd[0], EVFILT_READ, EV_DELETE, 0, 0, NULL); if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) fail(errno, "kevent", socktype, "EVFILT_READ, EV_DELETE"); OK("EVFILT_READ, EV_DELETE"); }
void uv__io_poll(uv_loop_t* loop, int timeout) { struct kevent events[1024]; struct kevent* ev; struct timespec spec; unsigned int nevents; unsigned int revents; QUEUE* q; uint64_t base; uint64_t diff; uv__io_t* w; int filter; int fflags; int count; int nfds; int fd; int op; int i; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); return; } nevents = 0; while (!QUEUE_EMPTY(&loop->watcher_queue)) { q = QUEUE_HEAD(&loop->watcher_queue); QUEUE_REMOVE(q); QUEUE_INIT(q); w = QUEUE_DATA(q, uv__io_t, watcher_queue); assert(w->pevents != 0); assert(w->fd >= 0); assert(w->fd < (int) loop->nwatchers); if ((w->events & UV__POLLIN) == 0 && (w->pevents & UV__POLLIN) != 0) { filter = EVFILT_READ; fflags = 0; op = EV_ADD; if (w->cb == uv__fs_event) { filter = EVFILT_VNODE; fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE; op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */ } EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0); if (++nevents == ARRAY_SIZE(events)) { if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) abort(); nevents = 0; } } if ((w->events & UV__POLLOUT) == 0 && (w->pevents & UV__POLLOUT) != 0) { EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (++nevents == ARRAY_SIZE(events)) { if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) abort(); nevents = 0; } } w->events = w->pevents; } assert(timeout >= -1); base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ for (;; nevents = 0) { if (timeout != -1) { spec.tv_sec = timeout / 1000; spec.tv_nsec = (timeout % 1000) * 1000000; } nfds = kevent(loop->backend_fd, events, nevents, events, ARRAY_SIZE(events), timeout == -1 ? NULL : &spec); /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the * operating system didn't reschedule our process while in the syscall. */ SAVE_ERRNO(uv__update_time(loop)); if (nfds == 0) { assert(timeout != -1); return; } if (nfds == -1) { if (errno != EINTR) abort(); if (timeout == 0) return; if (timeout == -1) continue; /* Interrupted by a signal. Update timeout and poll again. */ goto update_timeout; } nevents = 0; assert(loop->watchers != NULL); loop->watchers[loop->nwatchers] = (void*) events; loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; for (i = 0; i < nfds; i++) { ev = events + i; fd = ev->ident; /* Skip invalidated events, see uv__platform_invalidate_fd */ if (fd == -1) continue; w = loop->watchers[fd]; if (w == NULL) { /* File descriptor that we've stopped watching, disarm it. */ /* TODO batch up */ struct kevent events[1]; EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) if (errno != EBADF && errno != ENOENT) abort(); continue; } if (ev->filter == EVFILT_VNODE) { assert(w->events == UV__POLLIN); assert(w->pevents == UV__POLLIN); w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ nevents++; continue; } revents = 0; if (ev->filter == EVFILT_READ) { if (w->pevents & UV__POLLIN) { revents |= UV__POLLIN; w->rcount = ev->data; } else { /* TODO batch up */ struct kevent events[1]; EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) if (errno != ENOENT) abort(); } } if (ev->filter == EVFILT_WRITE) { if (w->pevents & UV__POLLOUT) { revents |= UV__POLLOUT; w->wcount = ev->data; } else { /* TODO batch up */ struct kevent events[1]; EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) if (errno != ENOENT) abort(); } } if (ev->flags & EV_ERROR) revents |= UV__POLLERR; if (revents == 0) continue; w->cb(loop, w, revents); nevents++; } loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ timeout = 0; continue; } return; } if (timeout == 0) return; if (timeout == -1) continue; update_timeout: assert(timeout > 0); diff = loop->time - base; if (diff >= (uint64_t) timeout) return; timeout -= diff; } }
static void tp_kqueue_wait (gpointer p) { SocketIOData *socket_io_data; int kfd; struct kevent *events, *evt; int ready = 0, i; gpointer async_results [KQUEUE_NEVENTS * 2]; // * 2 because each loop can add up to 2 results here gint nresults; tp_kqueue_data *data; socket_io_data = p; data = socket_io_data->event_data; kfd = data->fd; events = g_new0 (struct kevent, KQUEUE_NEVENTS); while (1) { mono_gc_set_skip_thread (TRUE); do { if (ready == -1) { check_for_interruption_critical (); } ready = kevent (kfd, NULL, 0, events, KQUEUE_NEVENTS, NULL); } while (ready == -1 && errno == EINTR); mono_gc_set_skip_thread (FALSE); if (ready == -1) { int err = errno; g_free (events); if (err != EBADF) g_warning ("kevent wait: %d %s", err, g_strerror (err)); return; } mono_mutex_lock (&socket_io_data->io_lock); if (socket_io_data->inited == 3) { g_free (events); mono_mutex_unlock (&socket_io_data->io_lock); return; /* cleanup called */ } nresults = 0; for (i = 0; i < ready; i++) { int fd; MonoMList *list; MonoObject *ares; evt = &events [i]; fd = evt->ident; list = mono_g_hash_table_lookup (socket_io_data->sock_to_state, GINT_TO_POINTER (fd)); if (list != NULL && (evt->filter == EVFILT_READ || (evt->flags & EV_ERROR) != 0)) { ares = get_io_event (&list, MONO_POLLIN); if (ares != NULL) async_results [nresults++] = ares; } if (list != NULL && (evt->filter == EVFILT_WRITE || (evt->flags & EV_ERROR) != 0)) { ares = get_io_event (&list, MONO_POLLOUT); if (ares != NULL) async_results [nresults++] = ares; } if (list != NULL) { int p; mono_g_hash_table_replace (socket_io_data->sock_to_state, GINT_TO_POINTER (fd), list); p = get_events_from_list (list); if (evt->filter == EVFILT_READ && (p & MONO_POLLIN) != 0) { EV_SET (evt, fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0); kevent_change (kfd, evt, "READD read"); } if (evt->filter == EVFILT_WRITE && (p & MONO_POLLOUT) != 0) { EV_SET (evt, fd, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0); kevent_change (kfd, evt, "READD write"); } } else { mono_g_hash_table_remove (socket_io_data->sock_to_state, GINT_TO_POINTER (fd)); } } mono_mutex_unlock (&socket_io_data->io_lock); threadpool_append_jobs (&async_io_tp, (MonoObject **) async_results, nresults); mono_gc_bzero_aligned (async_results, sizeof (gpointer) * nresults); } }
EXPORT void* kqueue_loop(int kp) { struct kevent ke; /* event that was triggered */ int i, list, ret, handled; mach_port_t task; exc_msg_t *exc; int infoPid = kp; task_for_pid(current_task(), infoPid, &task); interface* face = find_interface(task); DEBUG_PRINT("[+kqueue_loop] KQUEUE PID of prog: %d\n", infoPid); face->kq = kqueue(); /* create a new kernel event queue */ if (face->kq == -1) { fprintf(stderr, "[-kqueue_loop] %d\n", face->kq); } /* initalize kevent structure */ EV_SET(&ke, infoPid, EVFILT_PROC, EV_ADD | EV_ENABLE, NOTE_SIGNAL | NOTE_FORK | NOTE_EXIT | NOTE_EXEC , 0, 0); i = kevent(face->kq, &ke, 1, NULL, 0, NULL); //adding event if (face->kq == -1) { fprintf(stderr, "[-kqueue_loop] %d\n", face->kq); } for(;;) { i = kevent(face->kq, NULL, 0, &ke, 1, NULL); //checking for change kevent if (i==-1) { DEBUG_PRINT("[+kqueue_loop] kevent stopped, exit from kqueue_loop thread: %d\n", 1); return "KEVENT_STOPPED"; } task_suspend(task); exc = malloc(sizeof(exc_msg_t)); exc->task = task; exc->exception = ke.fflags; //REGISTER EXCEPTION HANDLER LOOP THROUGH EXCEPTION LIST CALLING EXCEPTION HANDLED FUNCITONS FIRST for(list = 0; list < face->current_exception; list++) { if(face->except_list[list]->exception & ke.fflags) { handled = 1; ret = face->except_list[list]->handler(exc); if(ret == -1) { fprintf(stderr, "[-kqueue_loop] UNABLE TO HANDLE EVENT: %d\n", ke.fflags); exit(-1); } } } if(handled == 0) { DEBUG_PRINT("[-kqueue_loop] FAILED TO HANDLE :/ %d\n", 0); task_resume(task); continue; } handled = 0; task_resume(task); } }
/* Register a new socket's readable event to poller, edge_trigger */ int ev_add_event(int poller_fd, int fd) { struct kevent ke; EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL); return kevent(poller_fd, &ke, 1, NULL, 0, NULL); }
static int swReactorKqueue_set(swReactor *reactor, int fd, int fdtype) { swReactorKqueue *this = reactor->object; struct kevent e; swFd fd_; int ret; bzero(&e, sizeof(e)); int fflags = 0; fd_.fd = fd; fd_.fdtype = swReactor_fdtype(fdtype); if (swReactor_event_read(fdtype)) { #ifdef NOTE_EOF fflags = NOTE_EOF; #endif EV_SET(&e, fd, EVFILT_READ, EV_ADD, fflags, 0, NULL); memcpy(&e.udata, &fd_, sizeof(swFd)); ret = kevent(this->epfd, &e, 1, NULL, 0, NULL); if (ret < 0) { swSysError("kqueue->set(%d, SW_EVENT_READ) failed.", fd); return SW_ERR; } } else { EV_SET(&e, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); memcpy(&e.udata, &fd_, sizeof(swFd)); ret = kevent(this->epfd, &e, 1, NULL, 0, NULL); if (ret < 0) { swSysError("kqueue->del(%d, SW_EVENT_READ) failed.", fd); return SW_ERR; } } if (swReactor_event_write(fdtype)) { EV_SET(&e, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL); memcpy(&e.udata, &fd_, sizeof(swFd)); ret = kevent(this->epfd, &e, 1, NULL, 0, NULL); if (ret < 0) { swSysError("kqueue->set(%d, SW_EVENT_WRITE) failed.", fd); return SW_ERR; } } else { EV_SET(&e, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); memcpy(&e.udata, &fd_, sizeof(swFd)); ret = kevent(this->epfd, &e, 1, NULL, 0, NULL); if (ret < 0) { swSysError("kqueue->del(%d, SW_EVENT_WRITE) failed.", fd); return SW_ERR; } } swTraceLog(SW_TRACE_EVENT, "[THREAD #%d]EP=%d|FD=%d, events=%d", SwooleTG.id, this->epfd, fd, fdtype); //execute parent method swReactor_set(reactor, fd, fdtype); return SW_OK; }
int main(int argc, char *argv[]) { const char *fname = apmdev; int ctl_fd, sock_fd, ch, suspends, standbys, resumes; int statonly = 0; int powerstatus = 0, powerbak = 0, powerchange = 0; int noacsleep = 0; struct timespec ts = {TIMO, 0}, sts = {0, 0}; struct apm_power_info pinfo; time_t apmtimeout = 0; const char *sockname = sockfile; int kq, nchanges; struct kevent ev[2]; int ncpu_mib[2] = { CTL_HW, HW_NCPU }; int ncpu; size_t ncpu_sz = sizeof(ncpu); while ((ch = getopt(argc, argv, "aACdHLsf:t:S:")) != -1) switch(ch) { case 'a': noacsleep = 1; break; case 'd': debug = 1; break; case 'f': fname = optarg; break; case 'S': sockname = optarg; break; case 't': ts.tv_sec = strtoul(optarg, NULL, 0); if (ts.tv_sec == 0) usage(); break; case 's': /* status only */ statonly = 1; break; case 'A': if (doperf != PERF_NONE) usage(); doperf = PERF_AUTO; break; case 'C': if (doperf != PERF_NONE) usage(); doperf = PERF_COOL; break; case 'L': if (doperf != PERF_NONE) usage(); doperf = PERF_MANUAL; setperf(PERFMIN); break; case 'H': if (doperf != PERF_NONE) usage(); doperf = PERF_MANUAL; setperf(PERFMAX); break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc != 0) usage(); if (doperf == PERF_NONE) doperf = PERF_MANUAL; if (debug) openlog(__progname, LOG_CONS, LOG_LOCAL1); else { if (daemon(0, 0) < 0) error("failed to daemonize", NULL); openlog(__progname, LOG_CONS, LOG_DAEMON); setlogmask(LOG_UPTO(LOG_NOTICE)); } (void) signal(SIGTERM, sigexit); (void) signal(SIGHUP, sigexit); (void) signal(SIGINT, sigexit); if ((ctl_fd = open(fname, O_RDWR)) == -1) { if (errno != ENXIO && errno != ENOENT) error("cannot open device file `%s'", fname); } else if (fcntl(ctl_fd, F_SETFD, 1) == -1) error("cannot set close-on-exec for `%s'", fname); sock_fd = bind_socket(sockname); if (fcntl(sock_fd, F_SETFD, 1) == -1) error("cannot set close-on-exec for the socket", NULL); power_status(ctl_fd, 1, &pinfo); if (statonly) exit(0); set_driver_messages(ctl_fd, APM_PRINT_OFF); kq = kqueue(); if (kq <= 0) error("kqueue", NULL); EV_SET(&ev[0], sock_fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, NULL); if (ctl_fd == -1) nchanges = 1; else { EV_SET(&ev[1], ctl_fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, NULL); nchanges = 2; } if (kevent(kq, ev, nchanges, NULL, 0, &sts) < 0) error("kevent", NULL); if (sysctl(ncpu_mib, 2, &ncpu, &ncpu_sz, NULL, 0) < 0) error("cannot read hw.ncpu", NULL); if (doperf == PERF_AUTO || doperf == PERF_COOL) { setperf(0); setperf(100); } for (;;) { int rv; sts = ts; if (doperf == PERF_AUTO || doperf == PERF_COOL) { sts.tv_sec = 1; perf_status(&pinfo, ncpu); } apmtimeout += sts.tv_sec; if ((rv = kevent(kq, NULL, 0, ev, 1, &sts)) < 0) break; if (apmtimeout >= ts.tv_sec) { apmtimeout = 0; /* wakeup for timeout: take status */ powerbak = power_status(ctl_fd, 0, &pinfo); if (powerstatus != powerbak) { powerstatus = powerbak; powerchange = 1; } } if (!rv) continue; if (ev->ident == ctl_fd) { suspends = standbys = resumes = 0; syslog(LOG_DEBUG, "apmevent %04x index %d", APM_EVENT_TYPE(ev->data), APM_EVENT_INDEX(ev->data)); switch (APM_EVENT_TYPE(ev->data)) { case APM_SUSPEND_REQ: case APM_USER_SUSPEND_REQ: case APM_CRIT_SUSPEND_REQ: case APM_BATTERY_LOW: suspends++; break; case APM_USER_STANDBY_REQ: case APM_STANDBY_REQ: standbys++; break; #if 0 case APM_CANCEL: suspends = standbys = 0; break; #endif case APM_NORMAL_RESUME: case APM_CRIT_RESUME: case APM_SYS_STANDBY_RESUME: powerbak = power_status(ctl_fd, 0, &pinfo); if (powerstatus != powerbak) { powerstatus = powerbak; powerchange = 1; } resumes++; break; case APM_POWER_CHANGE: powerbak = power_status(ctl_fd, 0, &pinfo); if (powerstatus != powerbak) { powerstatus = powerbak; powerchange = 1; } break; default: ; } if ((standbys || suspends) && noacsleep && power_status(ctl_fd, 0, &pinfo)) syslog(LOG_DEBUG, "no! sleep! till brooklyn!"); else if (suspends) suspend(ctl_fd); else if (standbys) stand_by(ctl_fd); else if (resumes) { do_etc_file(_PATH_APM_ETC_RESUME); syslog(LOG_NOTICE, "system resumed from APM sleep"); } if (powerchange) { if (powerstatus) do_etc_file(_PATH_APM_ETC_POWERUP); else do_etc_file(_PATH_APM_ETC_POWERDOWN); powerchange = 0; } } else if (ev->ident == sock_fd) switch (handle_client(sock_fd, ctl_fd)) { case NORMAL: break; case SUSPENDING: suspend(ctl_fd); break; case STANDING_BY: stand_by(ctl_fd); break; case HIBERNATING: hibernate(ctl_fd); break; } } error("kevent loop", NULL); return 1; }