add improved argument parsing. also add helper messages
[archipelago] / xseg / peers / user / peer.c
index dee48e8..451ea41 100644 (file)
@@ -3,24 +3,30 @@
 #include <stdlib.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include <xseg/xseg.h>
-#include <peer.h>
 #include <sys/syscall.h>
 #include <sys/time.h>
 #include <signal.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <errno.h>
+
 #ifdef MT
 #include <pthread.h>
 #endif
 
+#include <xseg/xseg.h>
+#include <peer.h>
+
 #ifdef MT
 #define PEER_TYPE "pthread"
 #else
 #define PEER_TYPE "posix"
 #endif
 
+//FIXME this should not be defined here probably
+#define MAX_SPEC_LEN 128
+#define MAX_PIDFILE_LEN 512
+
 volatile unsigned int terminated = 0;
 unsigned int verbose = 0;
 struct log_ctx lc;
@@ -29,6 +35,8 @@ uint32_t ta = 0;
 #endif
 
 #ifdef MT
+struct peerd *global_peer;
+
 struct thread {
        struct peerd *peer;
        pthread_t tid;
@@ -79,7 +87,8 @@ static inline int isTerminate()
 {
 /* ta doesn't need to be taken into account, because the main loops
  * doesn't check the terminated flag if ta is not 0.
- *
+ */
+       /*
 #ifdef ST_THREADS
        return (!ta & terminated);
 #else
@@ -93,12 +102,24 @@ void signal_handler(int signal)
 {
        XSEGLOG2(&lc, I, "Caught signal. Terminating gracefully");
        terminated = 1;
+#ifdef MT
+       wake_up_next_thread(global_peer);
+#endif
+}
+
+void renew_logfile(int signal)
+{
+       XSEGLOG2(&lc, I, "Caught signal. Renewing logfile");
+       renew_logctx(&lc, NULL, verbose, NULL, REOPEN_FILE);
 }
 
-static int setup_signals()
+static int setup_signals(struct peerd *peer)
 {
        int r;
        struct sigaction sa;
+#ifdef MT
+       global_peer = peer;
+#endif
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;
        sa.sa_handler = signal_handler;
@@ -111,6 +132,12 @@ static int setup_signals()
        r = sigaction(SIGQUIT, &sa, NULL);
        if (r < 0)
                return r;
+
+       sa.sa_handler = renew_logfile;
+       r = sigaction(SIGUSR1, &sa, NULL);
+       if (r < 0)
+               return r;
+
        return r;
 }
 
@@ -372,7 +399,7 @@ static void* thread_loop(void *arg)
        pid_t pid =syscall(SYS_gettid);
        uint64_t loops;
        uint64_t threshold=1000/(1 + portno_end - portno_start);
-       
+
        XSEGLOG2(&lc, D, "thread %u\n",  (unsigned int) (t- peer->thread));
 
        XSEGLOG2(&lc, I, "Thread %u has tid %u.\n", (unsigned int) (t- peer->thread), pid);
@@ -398,6 +425,7 @@ static void* thread_loop(void *arg)
                xseg_cancel_wait(xseg, peer->portno_start);
                XSEGLOG2(&lc, I, "Thread %u woke up\n", (unsigned int) (t- peer->thread));
        }
+       wake_up_next_thread(peer);
        return NULL;
 }
 
@@ -443,7 +471,7 @@ static int peerd_loop(struct peerd *peer)
        uint64_t threshold=1000/(1 + portno_end - portno_start);
        pid_t pid =syscall(SYS_gettid);
        uint64_t loops;
-       
+
        XSEGLOG2(&lc, I, "Peer has tid %u.\n", pid);
        xseg_init_local_signal(xseg, peer->portno_start);
        for (;!(isTerminate() && xq_count(&peer->free_reqs) == peer->nr_ops);) {
@@ -533,7 +561,7 @@ malloc_fail:
        peer->portno_end= (xport) portno_end;
        port = xseg_bind_port(peer->xseg, peer->portno_start, NULL);
        if (!port){
-               printf("cannot bind to port %ld\n", peer->portno_start);
+               printf("cannot bind to port %u\n", (unsigned int) peer->portno_start);
                return NULL;
        }
 
@@ -542,7 +570,7 @@ malloc_fail:
                struct xseg_port *tmp;
                tmp = xseg_bind_port(peer->xseg, p, (void *)xseg_get_signal_desc(peer->xseg, port));
                if (!tmp){
-                       printf("cannot bind to port %ld\n", p);
+                       printf("cannot bind to port %u\n", (unsigned int) p);
                        return NULL;
                }
        }
@@ -575,7 +603,7 @@ int pidfile_remove(char *path, int fd)
 int pidfile_write(int pid_fd)
 {
        char buf[16];
-       snprintf(buf, sizeof(buf), "%d", syscall(SYS_gettid));
+       snprintf(buf, sizeof(buf), "%ld", syscall(SYS_gettid));
        buf[15] = 0;
        
        lseek(pid_fd, 0, SEEK_SET);
@@ -617,28 +645,60 @@ int pidfile_open(char *path, pid_t *old_pid)
        return fd;
 }
 
+void usage(char *argv0)
+{
+       fprintf(stderr, "Usage: %s [general options] [custom peer options]\n\n", argv0);
+       fprintf(stderr, "General peer options:\n"
+               "  Option      | Default | \n"
+               "  --------------------------------------------\n"
+               "    -g        | None    | Segment spec to join\n"
+               "    -sp       | NoPort  | Start portno to bind\n"
+               "    -ep       | NoPort  | End portno to bind\n"
+               "    -p        | NoPort  | Portno to bind\n"
+               "    -n        | 16      | Number of ops\n"
+               "    -v        | 0       | Verbosity level\n"
+               "    -l        | None    | Logfile \n"
+               "    -d        | No      | Daemonize \n"
+               "    --pidfile | None    | Pidfile \n"
+#ifdef MT
+               "    -t        | No      | Number of threads \n"
+#endif
+               "\n"
+              );
+       custom_peer_usage();
+}
+
 int main(int argc, char *argv[])
 {
        struct peerd *peer = NULL;
        //parse args
-       char *spec = "";
-       int i, r, daemonize = 0;
+       int r;
        long portno_start = -1, portno_end = -1, portno = -1;
+
        //set defaults here
+       int daemonize = 0, help = 0;
        uint32_t nr_ops = 16;
-       uint32_t nr_threads = 16 ;
+       uint32_t nr_threads = 1;
        unsigned int debug_level = 0;
        uint32_t defer_portno = NoPort;
-       char *logfile = NULL;
-       char *pidfile = NULL;
        pid_t old_pid;
        int pid_fd = -1;
 
+       char spec[MAX_SPEC_LEN + 1];
+       char logfile[MAX_LOGFILE_LEN + 1];
+       char pidfile[MAX_PIDFILE_LEN + 1];
+
+       logfile[0] = 0;
+       pidfile[0] = 0;
+       spec[0] = 0;
+
        //capture here -g spec, -n nr_ops, -p portno, -t nr_threads -v verbose level
        // -dp xseg_portno to defer blocking requests
        // -l log file ?
        //TODO print messages on arg parsing error
-       
+       //TODO string checking
+
+       /*
        for (i = 1; i < argc; i++) {
                if (!strcmp(argv[i], "-g") && i + 1 < argc) {
                        spec = argv[i+1];
@@ -651,7 +711,7 @@ int main(int argc, char *argv[])
                        i += 1;
                        continue;
                }
-               
+
                if (!strcmp(argv[i], "-ep") && i + 1 < argc) {
                        portno_end = strtoul(argv[i+1], NULL, 10);
                        i += 1;
@@ -700,10 +760,39 @@ int main(int argc, char *argv[])
                }
 
        }
-       init_logctx(&lc, argv[0], debug_level, logfile);
+       */
+       BEGIN_READ_ARGS(argc, argv);
+       READ_ARG_STRING("-g", spec, MAX_SPEC_LEN);
+       READ_ARG_ULONG("-sp", portno_start);
+       READ_ARG_ULONG("-ep", portno_end);
+       READ_ARG_ULONG("-p", portno);
+       READ_ARG_ULONG("-n", nr_ops);
+       READ_ARG_ULONG("-v", debug_level);
+#ifdef MT
+       READ_ARG_ULONG("-t", nr_threads);
+#endif
+//     READ_ARG_ULONG("-dp", defer_portno);
+       READ_ARG_STRING("-l", logfile, MAX_LOGFILE_LEN);
+       READ_ARG_BOOL("-d", daemonize);
+       READ_ARG_BOOL("-h", help);
+       READ_ARG_BOOL("--help", help);
+       READ_ARG_STRING("--pidfile", pidfile, MAX_PIDFILE_LEN);
+       END_READ_ARGS();
+
+       if (help){
+               usage(argv[0]);
+               return 0;
+       }
+
+       r = init_logctx(&lc, argv[0], debug_level, logfile,
+                       REDIRECT_STDOUT|REDIRECT_STDERR);
+       if (r < 0){
+               XSEGLOG("Cannot initialize logging to logfile");
+               return -1;
+       }
        XSEGLOG2(&lc, D, "Main thread has tid %ld.\n", syscall(SYS_gettid));
-       
-       if (pidfile){
+
+       if (pidfile[0]){
                pid_fd = pidfile_open(pidfile, &old_pid);
                if (pid_fd < 0) {
                        if (old_pid) {
@@ -714,7 +803,7 @@ int main(int argc, char *argv[])
                        return -1;
                }
        }
-       
+
        if (daemonize){
                if (daemon(0, 1) < 0){
                        XSEGLOG2(&lc, E, "Cannot daemonize");
@@ -724,7 +813,7 @@ int main(int argc, char *argv[])
        }
 
        pidfile_write(pid_fd);
-       
+
        //TODO perform argument sanity checks
        verbose = debug_level;
        if (portno != -1) {
@@ -732,17 +821,17 @@ int main(int argc, char *argv[])
                portno_end = portno;
        }
 
-       setup_signals();
-       //TODO err check
        peer = peerd_init(nr_ops, spec, portno_start, portno_end, nr_threads, defer_portno);
        if (!peer){
                r = -1;
                goto out;
        }
+       setup_signals(peer);
        r = custom_peer_init(peer, argc, argv);
        if (r < 0)
                goto out;
 #ifdef MT
+       //TODO err check
        peerd_start_threads(peer);
 #endif