void async_wait(struct async *self) { int i; pthread_mutex_lock(&self->lock); self->shutdown = 1; pthread_mutex_unlock(&self->lock); pthread_cond_broadcast(&self->notify); for (i = 0; i < self->thread_num; i++) pthread_join(self->threads[i], NULL); async_destroy(self); }
/** * \brief Waits for an Async object to finish up (joins all the threads * in the thread pool) and DESTROYS the Async object (frees its * memory and resources). * * This function will wait forever or until a signal is received and all * the tasks in the queue have been processed. */ static void async_wait(async_p async) { if (!async) return; /* wake threads (just in case) by sending `async->count` * number of wakeups */ if (async->pipe.out) write(async->pipe.out, async, async->count); /* join threads */ for (int i = 0; i < async->count; i++) { join_thread(async->threads[i]); } /* perform any pending tasks */ perform_tasks(async); /* release queue memory and resources */ async_destroy(async); }
int main(int const argc, char const *const *const argv) { // Depending on how async_pool and async_fs are configured, we might be // using our own thread pool heavily or not. However, at the minimum, // uv_getaddrinfo uses the libuv thread pool, and it blocks on the // network, so don't set this number too low. if(!getenv("UV_THREADPOOL_SIZE")) putenv((char *)"UV_THREADPOOL_SIZE=4"); raiserlimit(); async_init(); int rc = tls_init(); if(rc < 0) { alogf("TLS initialization error: %s\n", strerror(errno)); return 1; } if(2 != argc || '-' == argv[1][0]) { alogf("Usage:\n\t" "%s repo\n", argv[0]); return 1; } path = argv[1]; // Even our init code wants to use async I/O. async_spawn(STACK_DEFAULT, init, NULL); uv_run(async_loop, UV_RUN_DEFAULT); async_spawn(STACK_DEFAULT, term, NULL); uv_run(async_loop, UV_RUN_DEFAULT); // cleanup is separate from term because connections might // still be active. async_spawn(STACK_DEFAULT, cleanup, NULL); uv_run(async_loop, UV_RUN_DEFAULT); async_destroy(); // TODO: Windows? if(sig) raise(sig); return 0; }
int main ( int argc, char* argv[] ) { pgm_error_t* pgm_err = NULL; setlocale (LC_ALL, ""); #ifndef _WIN32 puts ("いちごのショートケーキ"); #else puts ("ichigo no shōtokēki"); #endif if (!pgm_init (&pgm_err)) { fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message); pgm_error_free (pgm_err); return EXIT_FAILURE; } /* parse program arguments */ #ifdef _WIN32 const char* binary_name = strrchr (argv[0], '\\'); #else const char* binary_name = strrchr (argv[0], '/'); #endif if (NULL == binary_name) binary_name = argv[0]; else binary_name++; int c; while ((c = getopt (argc, argv, "s:n:p:f:K:N:lih")) != -1) { switch (c) { case 'n': network = optarg; break; case 's': port = atoi (optarg); break; case 'p': udp_encap_port = atoi (optarg); break; case 'f': use_fec = TRUE; break; case 'K': rs_k = atoi (optarg); break; case 'N': rs_n = atoi (optarg); break; case 'l': use_multicast_loop = TRUE; break; case 'i': pgm_if_print_all(); return EXIT_SUCCESS; case 'h': case '?': usage (binary_name); } } if (use_fec && ( !rs_n || !rs_k )) { fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k); usage (binary_name); } /* setup signal handlers */ #ifdef SIGHUP signal (SIGHUP, SIG_IGN); #endif #ifndef _WIN32 int e = pipe (terminate_pipe); assert (0 == e); signal (SIGINT, on_signal); signal (SIGTERM, on_signal); #else terminateEvent = WSACreateEvent (); SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); setvbuf (stdout, (char *) NULL, _IONBF, 0); #endif /* !_WIN32 */ if (!on_startup()) { fprintf (stderr, "Startup failed\n"); return EXIT_FAILURE; } /* dispatch loop */ #ifndef _WIN32 int fds, read_fd = async_get_socket (async); fd_set readfds; #else DWORD cEvents = 2; WSAEVENT waitEvents[ 2 ]; DWORD dwEvents; waitEvents[0] = terminateEvent; waitEvents[1] = async_get_event (async); #endif /* !_WIN32 */ puts ("Entering PGM message loop ... "); do { char buffer[4096]; struct pgm_sockaddr_t from; socklen_t fromlen = sizeof (from); const ssize_t len = async_recvfrom (async, buffer, sizeof(buffer), &from, &fromlen); if (len >= 0) { on_data (buffer, len, &from); } else { #ifndef _WIN32 fds = MAX(terminate_pipe[0], read_fd) + 1; FD_ZERO(&readfds); FD_SET(terminate_pipe[0], &readfds); FD_SET(read_fd, &readfds); fds = select (fds, &readfds, NULL, NULL, NULL); #else dwEvents = WSAWaitForMultipleEvents (cEvents, waitEvents, FALSE, WSA_INFINITE, FALSE); switch (dwEvents) { case WSA_WAIT_EVENT_0+1: WSAResetEvent (waitEvents[1]); break; default: break; } #endif /* _WIN32 */ } } while (!is_terminated); puts ("Message loop terminated, cleaning up."); /* cleanup */ #ifndef _WIN32 close (terminate_pipe[0]); close (terminate_pipe[1]); #else WSACloseEvent (terminateEvent); #endif /* !_WIN32 */ if (async) { puts ("Destroying asynchronous queue."); async_destroy (async); async = NULL; } if (sock) { puts ("Closing PGM socket."); pgm_close (sock, TRUE); sock = NULL; } puts ("PGM engine shutdown."); pgm_shutdown (); puts ("finished."); return EXIT_SUCCESS; }