📄 cygserver.cc
字号:
version.major = CYGWIN_SERVER_VERSION_MAJOR; version.api = CYGWIN_SERVER_VERSION_API; version.minor = CYGWIN_SERVER_VERSION_MINOR; version.patch = CYGWIN_SERVER_VERSION_PATCH;}class server_request : public queue_request{public: server_request (transport_layer_base *const conn, process_cache *const cache) : _conn (conn), _cache (cache) {} virtual ~server_request () { safe_delete (_conn); } virtual void process () { client_request::handle_request (_conn, _cache); }private: transport_layer_base *const _conn; process_cache *const _cache;};class server_submission_loop : public queue_submission_loop{public: server_submission_loop (threaded_queue *const queue, transport_layer_base *const transport, process_cache *const cache) : queue_submission_loop (queue, false), _transport (transport), _cache (cache) { assert (_transport); assert (_cache); }private: transport_layer_base *const _transport; process_cache *const _cache; virtual void request_loop ();};/* FIXME: this is a little ugly. What we really want is to wait on * two objects: one for the pipe/socket, and one for being told to * shutdown. Otherwise this will stay a problem (we won't actually * shutdown until the request _AFTER_ the shutdown request. And * sending ourselves a request is ugly */voidserver_submission_loop::request_loop (){ /* I'd like the accepting thread's priority to be above any "normal" * thread in the system to avoid overflowing the listen queue (for * sockets; similar issues exist for named pipes); but, for example, * a normal priority thread in a foregrounded process is boosted to * THREAD_PRIORITY_HIGHEST (AFAICT). Thus try to set the current * thread's priority to a level one above that. This fails on * win9x/ME so assume any failure in that call is due to that and * simply call again at one priority level lower. */ if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST + 1)) if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST)) debug_printf ("failed to raise accept thread priority, error = %lu", GetLastError ()); while (_running) { bool recoverable = false; transport_layer_base *const conn = _transport->accept (&recoverable); if (!conn && !recoverable) { system_printf ("fatal error on IPC transport: closing down"); return; } // EINTR probably implies a shutdown request; so back off for a // moment to let the main thread take control, otherwise the // server spins here receiving EINTR repeatedly since the signal // handler in the main thread doesn't get a chance to be called. if (!conn && errno == EINTR) { if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL)) debug_printf ("failed to reset thread priority, error = %lu", GetLastError ()); Sleep (0); if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST + 1)) if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST)) debug_printf ("failed to raise thread priority, error = %lu", GetLastError ()); } if (conn) _queue->add (safe_new (server_request, conn, _cache)); }}client_request_shutdown::client_request_shutdown () : client_request (CYGSERVER_REQUEST_SHUTDOWN){ // verbose: syscall_printf ("created");}voidclient_request_shutdown::serve (transport_layer_base *, process_cache *){ assert (!error_code ()); if (msglen ()) syscall_printf ("unexpected request body ignored: %lu bytes", msglen ()); /* FIXME: link upwards, and then this becomes a trivial method call to * only shutdown _this queue_ */ kill (getpid (), SIGINT); msglen (0);}static sig_atomic_t shutdown_server = false;static voidhandle_signal (const int signum){ /* any signal makes us die :} */ shutdown_server = true;}/* * print_usage () */static voidprint_usage (const char *const pgm){ printf ("Usage: %s [OPTIONS]\n", pgm); printf (" -c, --cleanup-threads number of cleanup threads to use\n"); printf (" -h, --help output usage information and exit\n"); printf (" -r, --request-threads number of request threads to use\n"); printf (" -s, --shutdown shutdown the daemon\n"); printf (" -v, --version output version information and exit\n");}/* * print_version () */static voidprint_version (const char *const pgm){ char *vn = NULL; const char *const colon = strchr (version, ':'); if (!colon) { vn = strdup ("?"); } else { vn = strdup (colon + 2); // Skip ": " char *const spc = strchr (vn, ' '); if (spc) *spc = '\0'; } char buf[200]; snprintf (buf, sizeof (buf), "%d.%d.%d(%d.%d/%d/%d)-(%d.%d.%d.%d) %s", cygwin_version.dll_major / 1000, cygwin_version.dll_major % 1000, cygwin_version.dll_minor, cygwin_version.api_major, cygwin_version.api_minor, cygwin_version.shared_data, CYGWIN_SERVER_VERSION_MAJOR, CYGWIN_SERVER_VERSION_API, CYGWIN_SERVER_VERSION_MINOR, CYGWIN_SERVER_VERSION_PATCH, cygwin_version.mount_registry, cygwin_version.dll_build_date); printf ("%s (cygwin) %s\n", pgm, vn); printf ("API version %s\n", buf); printf ("Copyright 2001, 2002 Red Hat, Inc.\n"); printf ("Compiled on %s\n", __DATE__); free (vn);}/* * main () */intmain (const int argc, char *argv[]){ const struct option longopts[] = { {"cleanup-threads", required_argument, NULL, 'c'}, {"help", no_argument, NULL, 'h'}, {"request-threads", required_argument, NULL, 'r'}, {"shutdown", no_argument, NULL, 's'}, {"version", no_argument, NULL, 'v'}, {0, no_argument, NULL, 0} }; const char opts[] = "c:hr:sv"; int cleanup_threads = 2; int request_threads = 10; bool shutdown = false; const char *pgm = NULL; if (!(pgm = strrchr (*argv, '\\')) && !(pgm = strrchr (*argv, '/'))) pgm = *argv; else pgm++; wincap.init (); if (wincap.has_security ()) setup_privileges (); int opt; while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF) switch (opt) { case 'c': cleanup_threads = atoi (optarg); if (cleanup_threads <= 0) { fprintf (stderr, "%s: number of cleanup threads must be positive\n", pgm); exit (1); } break; case 'h': print_usage (pgm); return 0; case 'r': request_threads = atoi (optarg); if (request_threads <= 0) { fprintf (stderr, "%s: number of request threads must be positive\n", pgm); exit (1); } break; case 's': shutdown = true; break; case 'v': print_version (pgm); return 0; case '?': fprintf (stderr, "Try `%s --help' for more information.\n", pgm); exit (1); } if (optind != argc) { fprintf (stderr, "%s: too many arguments\n", pgm); exit (1); } if (shutdown) { /* Setting `cygserver_running' stops the request code making a * version request, which is not much to the point. */ cygserver_running = CYGSERVER_OK; client_request_shutdown req; if (req.make_request () == -1 || req.error_code ()) { fprintf (stderr, "%s: shutdown request failed: %s\n", pgm, strerror (req.error_code ())); exit (1); } // FIXME: It would be nice to wait here for the daemon to exit. return 0; }#define SIGHANDLE(SIG) \ do \ { \ struct sigaction act; \ \ act.sa_handler = &handle_signal; \ act.sa_mask = 0; \ act.sa_flags = 0; \ \ if (sigaction (SIG, &act, NULL) == -1) \ { \ system_printf ("failed to install handler for " #SIG ": %s", \ strerror (errno)); \ exit (1); \ } \ } while (false) SIGHANDLE (SIGHUP); SIGHANDLE (SIGINT); SIGHANDLE (SIGTERM); print_version (pgm); setbuf (stdout, NULL); printf ("daemon starting up"); threaded_queue request_queue (request_threads); printf ("."); transport_layer_base *const transport = create_server_transport (); assert (transport); printf ("."); process_cache cache (cleanup_threads); printf ("."); server_submission_loop submission_loop (&request_queue, transport, &cache); printf ("."); request_queue.add_submission_loop (&submission_loop); printf ("."); if (transport->listen () == -1) { exit (1); } printf ("."); cache.start (); printf ("."); request_queue.start (); printf ("."); printf ("complete\n"); /* TODO: wait on multiple objects - the thread handle for each * request loop + all the process handles. This should be done by * querying the request_queue and the process cache for all their * handles, and then waiting for (say) 30 seconds. after that we * recreate the list of handles to wait on, and wait again. the * point of all this abstraction is that we can trivially server * both sockets and pipes simply by making a new transport, and then * calling request_queue.process_requests (transport2); */ /* WaitForMultipleObjects abort && request_queue && process_queue && signal -- if signal event then retrigger it */ while (!shutdown_server && request_queue.running () && cache.running ()) pause (); printf ("\nShutdown request received - new requests will be denied\n"); request_queue.stop (); printf ("All pending requests processed\n"); safe_delete (transport); printf ("No longer accepting requests - cygwin will operate in daemonless mode\n"); cache.stop (); printf ("All outstanding process-cache activities completed\n"); printf ("daemon shutdown\n"); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -