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++;
	}
}
Exemple #2
0
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++;
}
Exemple #3
0
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++;
}
Exemple #4
0
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;
		}
	}
}
Exemple #5
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;
}
Exemple #6
0
/*
 * 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");
}
Exemple #7
0
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;
  }
}
Exemple #8
0
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);
	}
}
Exemple #9
0
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);
    }
}
Exemple #10
0
/* 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);
}
Exemple #11
0
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;
}
Exemple #12
0
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;
}