Пример #1
2
void
coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, long ssize)
{
  coro_context nctx;
# if CORO_SJLJ
  stack_t ostk, nstk;
  struct sigaction osa, nsa;
  sigset_t nsig, osig;
# endif

  if (!coro)
    return;

  coro_init_func = coro;
  coro_init_arg  = arg;

  new_coro    = ctx;
  create_coro = &nctx;

# if CORO_SJLJ
  /* we use SIGUSR2. first block it, then fiddle with it. */

  sigemptyset (&nsig);
  sigaddset (&nsig, SIGUSR2);
  sigprocmask (SIG_BLOCK, &nsig, &osig);

  nsa.sa_handler = trampoline;
  sigemptyset (&nsa.sa_mask);
  nsa.sa_flags = SA_ONSTACK;

  if (sigaction (SIGUSR2, &nsa, &osa))
    {
      perror ("sigaction");
      abort ();
    }

  /* set the new stack */
  nstk.ss_sp    = STACK_ADJUST_PTR (sptr, ssize); /* yes, some platforms (IRIX) get this wrong. */
  nstk.ss_size  = STACK_ADJUST_SIZE (sptr, ssize);
  nstk.ss_flags = 0;

  if (sigaltstack (&nstk, &ostk) < 0)
    {
      perror ("sigaltstack");
      abort ();
    }

  trampoline_done = 0;
  kill (getpid (), SIGUSR2);
  sigfillset (&nsig); sigdelset (&nsig, SIGUSR2);

  while (!trampoline_done)
    sigsuspend (&nsig);

  sigaltstack (0, &nstk);
  nstk.ss_flags = SS_DISABLE;
  if (sigaltstack (&nstk, 0) < 0)
    perror ("sigaltstack");

  sigaltstack (0, &nstk);
  if (~nstk.ss_flags & SS_DISABLE)
    abort ();

  if (~ostk.ss_flags & SS_DISABLE)
    sigaltstack (&ostk, 0);

  sigaction (SIGUSR2, &osa, 0);
  sigprocmask (SIG_SETMASK, &osig, 0);

# elif CORO_LOSER

  coro_setjmp (ctx->env);
  #if __CYGWIN__ && __i386
    ctx->env[8]                        = (long)    coro_init;
    ctx->env[7]                        = (long)    ((char *)sptr + ssize)         - sizeof (long);
  #elif __CYGWIN__ && __x86_64
    ctx->env[7]                        = (long)    coro_init;
    ctx->env[6]                        = (long)    ((char *)sptr + ssize)         - sizeof (long);
  #elif defined(__MINGW32__)
    ctx->env[5]                        = (long)    coro_init;
    ctx->env[4]                        = (long)    ((char *)sptr + ssize)         - sizeof (long);
  #elif defined(_M_IX86)
    ((_JUMP_BUFFER *)&ctx->env)->Eip   = (long)    coro_init;
    ((_JUMP_BUFFER *)&ctx->env)->Esp   = (long)    STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
  #elif defined(_M_AMD64)
    ((_JUMP_BUFFER *)&ctx->env)->Rip   = (__int64) coro_init;
    ((_JUMP_BUFFER *)&ctx->env)->Rsp   = (__int64) STACK_ADJUST_PTR (sptr, ssize) - sizeof (__int64);
  #elif defined(_M_IA64)
    ((_JUMP_BUFFER *)&ctx->env)->StIIP = (__int64) coro_init;
    ((_JUMP_BUFFER *)&ctx->env)->IntSp = (__int64) STACK_ADJUST_PTR (sptr, ssize) - sizeof (__int64);
  #else
    #error "microsoft libc or architecture not supported"
  #endif

# elif CORO_LINUX

  coro_setjmp (ctx->env);
  #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (JB_PC) && defined (JB_SP)
    ctx->env[0].__jmpbuf[JB_PC]        = (long)    coro_init;
    ctx->env[0].__jmpbuf[JB_SP]        = (long)    STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
  #elif __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (__mc68000__)
    ctx->env[0].__jmpbuf[0].__aregs[0] = (long int)coro_init;
    ctx->env[0].__jmpbuf[0].__sp       = (int *)   ((char *)sptr + ssize)         - sizeof (long);
  #elif defined (__GNU_LIBRARY__) && defined (__i386__)
    ctx->env[0].__jmpbuf[0].__pc       = (char *)  coro_init;
    ctx->env[0].__jmpbuf[0].__sp       = (void *)  ((char *)sptr + ssize)         - sizeof (long);
  #elif defined (__GNU_LIBRARY__) && defined (__amd64__)
    ctx->env[0].__jmpbuf[JB_PC]        = (long)    coro_init;
    ctx->env[0].__jmpbuf[0].__sp       = (void *)  ((char *)sptr + ssize)         - sizeof (long);
  #else
    #error "linux libc or architecture not supported"
  #endif

# elif CORO_IRIX

  coro_setjmp (ctx->env, 0);
  ctx->env[JB_PC]                      = (__uint64_t)coro_init;
  ctx->env[JB_SP]                      = (__uint64_t)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);

# elif CORO_ASM

  ctx->sp = (void **)(ssize + (char *)sptr);
  *--ctx->sp = (void *)abort; /* needed for alignment only */
  *--ctx->sp = (void *)coro_init;

  #if CORO_WIN_TIB
  *--ctx->sp = 0;                    /* ExceptionList */
  *--ctx->sp = (char *)sptr + ssize; /* StackBase */
  *--ctx->sp = sptr;                 /* StackLimit */
  #endif

  ctx->sp -= NUM_SAVED;
  memset (ctx->sp, 0, sizeof (*ctx->sp) * NUM_SAVED);

# elif CORO_UCONTEXT

  getcontext (&(ctx->uc));

  ctx->uc.uc_link           =  0;
  ctx->uc.uc_stack.ss_sp    = sptr;
  ctx->uc.uc_stack.ss_size  = (size_t)ssize;
  ctx->uc.uc_stack.ss_flags = 0;

  makecontext (&(ctx->uc), (void (*)())coro_init, 0);

# endif

  coro_transfer (create_coro, new_coro);
}
Пример #2
0
int main(int argc,char *argv[])
{
    char cmd[CMD_SIZE];
    pid_t childPid;
    sigset_t blockMask,emptyMask;
    struct sigaction sa;

    setbuf(stdout,NULL);    /* Disable buffering of stdout */

    memset(cmd,0,CMD_SIZE);
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = sigHandler;
    if (sigaction(SIGCHLD,&sa,NULL) == -1)
    {
        errExit("sigaction");
    }

    /* Block SIGCHLD to prevent its delivery if a child terminates
       before the parent commences the sigsupsend() */
    sigemptyset(&blockMask);
    sigaddset(&blockMask,SIGCHLD);
    if (sigprocmask(SIG_SETMASK,&blockMask,NULL) == -1)
    {
        errExit("sigprocmask");
    }
    
    printf("Parent PID=%ld\n",(long)getpid());

    switch(childPid = fork())
    {
    case -1:
        errExit("fork");
    case 0:   /* Child: immediately exits to become zombie */
        printf("Child (PID=%ld) exiting\n",(long)getpid());
        _exit(EXIT_SUCCESS);
    default:  /* Parent */

        sigemptyset(&emptyMask);
        if (sigsuspend(&emptyMask) == -1 && errno != EINTR)
        {
            errExit("sigsuspend");
        }
        
        snprintf(cmd,CMD_SIZE,"ps -c | grep %s",basename(argv[0]));
        cmd[CMD_SIZE - 1] = '\0';   /* Ensure string is null-terminated */
        system(cmd);               /* View zombie child */
        
        /* Now send the "sure kill" signal to the zombie */

        if (kill(childPid,SIGKILL) == -1)
        {
            errMsg("kill");
        }

        sleep(10);   /* Give child a chance to react to signal */
        printf("After sending SIGKILL to zombie (PID=%ld):\n",(long)childPid);
        system(cmd);   /* View zombie child again */
        
        exit(EXIT_SUCCESS);
    }
}
int main(int argc, char* const argv[]) {
    //place thread on the first cpu
    set_cpu(0);
    //initialize the custom memory allocator
    ssalloc_init();
    pthread_t *threads;
    pthread_attr_t attr;
    barrier_t barrier;
    pthread_mutex_t init_lock;
    struct timeval start, end;
    struct timespec timeout;

    thread_data_t *data;
    sigset_t block_set;

    //initially, set parameters to their default values
    num_threads = DEFAULT_NUM_THREADS;
    seed=DEFAULT_SEED;
    max_key=DEFAULT_RANGE;
    updates=DEFAULT_UPDATES;
    finds=DEFAULT_READS;
    //inserts=DEFAULT_INSERTS;
    //removes=DEFAULT_REMOVES;
    duration=DEFAULT_DURATION;

    //now read the parameters in case the user provided values for them 
    //we use getopt, the same skeleton may be used for other bechmarks,
    //though the particular parameters may be different
    struct option long_options[] = {
        // These options don't set a flag
        {"help",                      no_argument,       NULL, 'h'},
        {"duration",                  required_argument, NULL, 'd'},
        {"range",                     required_argument, NULL, 'r'},
        {"initial",                     required_argument, NULL, 'i'},
        {"num-threads",               required_argument, NULL, 'n'},
        {"updates",             required_argument, NULL, 'u'},
        {"seed",                      required_argument, NULL, 's'},
        {NULL, 0, NULL, 0}
    };

    int i,c;

    //actually get the parameters form the command-line
    while(1) {
        i = 0;
        c = getopt_long(argc, argv, "hd:n:l:u:i:r:s", long_options, &i);

        if(c == -1)
            break;

        if(c == 0 && long_options[i].flag == 0)
            c = long_options[i].val;

        switch(c) {
            case 0:
                /* Flag is automatically set */
                break;
            case 'h':
                printf("lock stress test\n"
                        "\n"
                        "Usage:\n"
                        "  stress_test [options...]\n"
                        "\n"
                        "Options:\n"
                        "  -h, --help\n"
                        "        Print this message\n"
                        "  -d, --duration <int>\n"
                        "        Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n"
                        "  -u, --updates <int>\n"
                        "        Percentage of update operations (default=" XSTR(DEFAULT_UPDATES) ")\n"
                        "  -r, --range <int>\n"
                        "        Key range (default=" XSTR(DEFAULT_RANGE) ")\n"
                        "  -n, --num-threads <int>\n"
                        "        Number of threads (default=" XSTR(DEFAULT_NUM_THREADS) ")\n"
                        "  -s, --seed <int>\n"
                        "        RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n"
                      );
                exit(0);
            case 'd':
                duration = atoi(optarg);
                break;
            case 'u':
                updates = atoi(optarg);
                finds = 100 - updates;
                break;
            case 'r':
                max_key = atoi(optarg);
                break;
            case 'i':
                break;
            case 'l':
                break;
            case 'n':
                num_threads = atoi(optarg);
                break;
            case 's':
                seed = atoi(optarg);
                break;
            case '?':
                printf("Use -h or --help for help\n");
                exit(0);
            default:
                exit(1);
        }
    }

    max_key--;
    //we round the max key up to the nearest power of 2, which makes our random key generation more efficient
    max_key = pow2roundup(max_key)-1;

    //initialization of the tree
    root = bst_initialize(num_threads);

    //initialize the data which will be passed to the threads
    if ((data = (thread_data_t *)malloc(num_threads * sizeof(thread_data_t))) == NULL) {
        perror("malloc");
        exit(1);
    }

    if ((threads = (pthread_t *)malloc(num_threads * sizeof(pthread_t))) == NULL) {
        perror("malloc");
        exit(1);
    }

    if (seed == 0)
        srand((int)time(NULL));
    else
        srand(seed);

    //flag signaling the threads until when to run
    *running = 1;

    //global barrier initialization (used to start the threads at the same time)
    barrier_init(&barrier, num_threads + 1);
    pthread_mutex_init(&init_lock, NULL);
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    timeout.tv_sec = duration / 1000;
    timeout.tv_nsec = (duration % 1000) * 1000000;
    

    //set the data for each thread and create the threads
    for (i = 0; i < num_threads; i++) {
        data[i].id = i;
        data[i].num_operations = 0;
        data[i].total_time=0;
        data[i].num_insert=0;
        data[i].num_remove=0;
        data[i].num_search=0;
        data[i].num_add = max_key/(2 * num_threads); 
        if (i< ((max_key/2)%num_threads)) data[i].num_add++;
        data[i].seed = rand();
        data[i].barrier = &barrier;
        data[i].init_lock = &init_lock;
        if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) {
            fprintf(stderr, "Error creating thread\n");
            exit(1);
        }
    }
    pthread_attr_destroy(&attr);

    /* Catch some signals */
    if (signal(SIGHUP, catcher) == SIG_ERR ||
            signal(SIGINT, catcher) == SIG_ERR ||
            signal(SIGTERM, catcher) == SIG_ERR) {
        perror("signal");
        exit(1);
    }

    // seeds = seed_rand();
    // skey_t key;
    // for (i=0;i<max_key/2;++i) {
    //     key = my_random(&seeds[0],&seeds[1],&seeds[2]) & max_key;
    //     //we make sure the insert was effective (as opposed to just updating an existing entry)
    //     if (bst_add(key, root, 0)!=TRUE) {
    //         i--;
    //     }
    // }

    // bst_print(root);


    /* Start threads */
    barrier_cross(&barrier);
    gettimeofday(&start, NULL);
    if (duration > 0) {
        //sleep for the duration of the experiment
        nanosleep(&timeout, NULL);
    } else {
        sigemptyset(&block_set);
        sigsuspend(&block_set);
    }

    //signal the threads to stop
    *running = 0;
    gettimeofday(&end, NULL);

    /* Wait for thread completion */
    for (i = 0; i < num_threads; i++) {
        if (pthread_join(threads[i], NULL) != 0) {
            fprintf(stderr, "Error waiting for thread completion\n");
            exit(1);
        }
    }
    DDPRINT("threads finshed\n",NULL);
    //compute the exact duration of the experiment
    duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000);
    
    //bst_print(root);

    unsigned long operations = 0;
    ticks total_ticks = 0;
    long reported_total = 1; //the tree contains two initial dummy nodes, INF1 and INF2
    //report some experiment statistics
    for (i = 0; i < num_threads; i++) {
        printf("Thread %d\n", i);
        printf("  #operations   : %lu\n", data[i].num_operations);
        printf("  #inserts   : %lu\n", data[i].num_insert);
        printf("  #removes   : %lu\n", data[i].num_remove);
        operations += data[i].num_operations;
        total_ticks += data[i].total_time;
        reported_total = reported_total + data[i].num_add + data[i].num_insert - data[i].num_remove;
    }

    printf("Duration      : %d (ms)\n", duration);
    printf("#txs     : %lu (%f / s)\n", operations, operations * 1000.0 / duration);
    //printf("Operation latency %lu\n", total_ticks / operations);
    //make sure the tree is correct
    printf("Expected size: %ld Actual size: %lu\n",reported_total,bst_size(root));

    free(threads);
    free(data);

    return 0;

}
Пример #4
0
ISC_APPFUNC_SCOPE isc_result_t
isc__app_ctxrun(isc_appctx_t *ctx0) {
	isc__appctx_t *ctx = (isc__appctx_t *)ctx0;
	int result;
	isc_event_t *event, *next_event;
	isc_task_t *task;
#ifdef USE_THREADS_SINGLECTX
	sigset_t sset;
	char strbuf[ISC_STRERRORSIZE];
#ifdef HAVE_SIGWAIT
	int sig;
#endif
#endif /* USE_THREADS_SINGLECTX */

	REQUIRE(VALID_APPCTX(ctx));

#ifdef HAVE_LINUXTHREADS
	REQUIRE(main_thread == pthread_self());
#endif

	LOCK(&ctx->lock);

	if (!ctx->running) {
		ctx->running = ISC_TRUE;

		/*
		 * Post any on-run events (in FIFO order).
		 */
		for (event = ISC_LIST_HEAD(ctx->on_run);
		     event != NULL;
		     event = next_event) {
			next_event = ISC_LIST_NEXT(event, ev_link);
			ISC_LIST_UNLINK(ctx->on_run, event, ev_link);
			task = event->ev_sender;
			event->ev_sender = NULL;
			isc_task_sendanddetach(&task, &event);
		}

	}

	UNLOCK(&ctx->lock);

#ifndef HAVE_SIGWAIT
	/*
	 * Catch SIGHUP.
	 *
	 * We do this here to ensure that the signal handler is installed
	 * (i.e. that it wasn't a "one-shot" handler).
	 */
	if (ctx == &isc_g_appctx) {
		result = handle_signal(SIGHUP, reload_action);
		if (result != ISC_R_SUCCESS)
			return (ISC_R_SUCCESS);
	}
#endif

#ifdef USE_THREADS_SINGLECTX
	/*
	 * When we are using multiple contexts, we don't rely on signals.
	 */
	if (ctx != &isc_g_appctx)
		return (ISC_R_SUCCESS);

	/*
	 * There is no danger if isc_app_shutdown() is called before we wait
	 * for signals.  Signals are blocked, so any such signal will simply
	 * be made pending and we will get it when we call sigwait().
	 */

	while (!ctx->want_shutdown) {
#ifdef HAVE_SIGWAIT
		/*
		 * Wait for SIGHUP, SIGINT, or SIGTERM.
		 */
		if (sigemptyset(&sset) != 0 ||
		    sigaddset(&sset, SIGHUP) != 0 ||
		    sigaddset(&sset, SIGINT) != 0 ||
		    sigaddset(&sset, SIGTERM) != 0) {
			isc__strerror(errno, strbuf, sizeof(strbuf));
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "isc_app_run() sigsetops: %s", strbuf);
			return (ISC_R_UNEXPECTED);
		}

#ifndef HAVE_UNIXWARE_SIGWAIT
		result = sigwait(&sset, &sig);
		if (result == 0) {
			if (sig == SIGINT || sig == SIGTERM)
				ctx->want_shutdown = ISC_TRUE;
			else if (sig == SIGHUP)
				ctx->want_reload = ISC_TRUE;
		}

#else /* Using UnixWare sigwait semantics. */
		sig = sigwait(&sset);
		if (sig >= 0) {
			if (sig == SIGINT || sig == SIGTERM)
				ctx->want_shutdown = ISC_TRUE;
			else if (sig == SIGHUP)
				ctx->want_reload = ISC_TRUE;
		}

#endif /* HAVE_UNIXWARE_SIGWAIT */
#else  /* Don't have sigwait(). */
		/*
		 * Listen for all signals.
		 */
		if (sigemptyset(&sset) != 0) {
			isc__strerror(errno, strbuf, sizeof(strbuf));
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "isc_app_run() sigsetops: %s",
					 strbuf);
			return (ISC_R_UNEXPECTED);
		}
		result = sigsuspend(&sset);
#endif /* HAVE_SIGWAIT */

		if (ctx->want_reload) {
			ctx->want_reload = ISC_FALSE;
			return (ISC_R_RELOAD);
		}

		if (ctx->want_shutdown && ctx->blocked)
			exit(1);
	}

#else /* USE_THREADS_SINGLECTX */

	(void)isc__taskmgr_dispatch(ctx->taskmgr);

	result = evloop(ctx);
	if (result != ISC_R_SUCCESS)
		return (result);

#endif /* USE_THREADS_SINGLECTX */

	return (ISC_R_SUCCESS);
}
Пример #5
0
static int
startServer(char *server[])
{
    sigset_t mask, old;
    const char * const *cpp;

    sigemptyset(&mask);
    sigaddset(&mask, SIGUSR1);
    sigprocmask(SIG_BLOCK, &mask, &old);

    serverpid = fork();

    switch(serverpid) {
    case 0:
        /* Unblock */
        sigprocmask(SIG_SETMASK, &old, NULL);

        /*
         * don't hang on read/write to control tty
         */
        signal(SIGTTIN, SIG_IGN);
        signal(SIGTTOU, SIG_IGN);
        /*
         * ignore SIGUSR1 in child.  The server
         * will notice this and send SIGUSR1 back
         * at xinit when ready to accept connections
         */
        signal(SIGUSR1, SIG_IGN);
        /*
         * prevent server from getting sighup from vhangup()
         * if client is xterm -L
         */
        setpgid(0,getpid());
        Execute(server);

        Error("unable to run server \"%s\"", server[0]);

        fprintf(stderr, "Use the -- option, or make sure that %s is in your path and\n", bindir);
        fprintf(stderr, "that \"%s\" is a program or a link to the right type of server\n", server[0]);
        fprintf(stderr, "for your display.  Possible server names include:\n\n");
        for (cpp = server_names; *cpp; cpp++)
            fprintf(stderr, "    %s\n", *cpp);
        fprintf(stderr, "\n");

        exit(EXIT_FAILURE);

        break;
    case -1:
        break;
    default:
        /*
         * don't nice server
         */
        setpriority(PRIO_PROCESS, serverpid, -1);

        errno = 0;
        if(! processTimeout(0, "")) {
            serverpid = -1;
            break;
        }
        /*
         * kludge to avoid race with TCP, giving server time to
         * set his socket options before we try to open it,
         * either use the 15 second timeout, or await SIGUSR1.
         *
         * If your machine is substantially slower than 15 seconds,
         * you can easily adjust this value.
         */
        alarm(15);

        sigsuspend(&old);
        alarm(0);
        sigprocmask(SIG_SETMASK, &old, NULL);

        if (waitforserver() == 0) {
            Error("unable to connect to X server");
            shutdown();
            serverpid = -1;
        }
        break;
    }

    return(serverpid);
}
Пример #6
0
/*
 * wait for job to complete or change state
 *
 * If jobs are compiled in then this routine expects sigchld to be blocked.
 */
static int
j_waitj(Job *j,
    int flags,			/* see JW_* */
    const char *where)
{
	int	rv;

	/*
	 * No auto-notify on the job we are waiting on.
	 */
	j->flags |= JF_WAITING;
	if (flags & JW_ASYNCNOTIFY)
		j->flags |= JF_W_ASYNCNOTIFY;

	if (!Flag(FMONITOR))
		flags |= JW_STOPPEDWAIT;

	while ((volatile int) j->state == PRUNNING ||
	    ((flags & JW_STOPPEDWAIT) && (volatile int) j->state == PSTOPPED)) {
		sigsuspend(&sm_default);
		if (fatal_trap) {
			int oldf = j->flags & (JF_WAITING|JF_W_ASYNCNOTIFY);
			j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY);
			runtraps(TF_FATAL);
			j->flags |= oldf; /* not reached... */
		}
		if ((flags & JW_INTERRUPT) && (rv = trap_pending())) {
			j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY);
			return -rv;
		}
	}
	j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY);

	if (j->flags & JF_FG) {
		int	status;

		j->flags &= ~JF_FG;
#ifdef JOBS
		if (Flag(FMONITOR) && ttypgrp_ok && j->pgrp) {
			/*
			 * Save the tty's current pgrp so it can be restored
			 * when the job is foregrounded.  This is to
			 * deal with things like the GNU su which does
			 * a fork/exec instead of an exec (the fork means
			 * the execed shell gets a different pid from its
			 * pgrp, so naturally it sets its pgrp and gets hosed
			 * when it gets foregrounded by the parent shell, which
			 * has restored the tty's pgrp to that of the su
			 * process).
			 */
			if (j->state == PSTOPPED &&
			    (j->saved_ttypgrp = tcgetpgrp(tty_fd)) >= 0)
				j->flags |= JF_SAVEDTTYPGRP;
			if (tcsetpgrp(tty_fd, our_pgrp) < 0) {
				warningf(true,
				    "j_waitj: tcsetpgrp(%d, %d) failed: %s",
				    tty_fd, (int) our_pgrp,
					strerror(errno));
			}
			if (j->state == PSTOPPED) {
				j->flags |= JF_SAVEDTTY;
				tcgetattr(tty_fd, &j->ttystate);
			}
		}
#endif /* JOBS */
		if (tty_fd >= 0) {
			/* Only restore tty settings if job was originally
			 * started in the foreground.  Problems can be
			 * caused by things like `more foobar &' which will
			 * typically get and save the shell's vi/emacs tty
			 * settings before setting up the tty for itself;
			 * when more exits, it restores the `original'
			 * settings, and things go down hill from there...
			 */
			if (j->state == PEXITED && j->status == 0 &&
			    (j->flags & JF_USETTYMODE)) {
				tcgetattr(tty_fd, &tty_state);
			} else {
				tcsetattr(tty_fd, TCSADRAIN, &tty_state);
				/* Don't use tty mode if job is stopped and
				 * later restarted and exits.  Consider
				 * the sequence:
				 *	vi foo (stopped)
				 *	...
				 *	stty something
				 *	...
				 *	fg (vi; ZZ)
				 * mode should be that of the stty, not what
				 * was before the vi started.
				 */
				if (j->state == PSTOPPED)
					j->flags &= ~JF_USETTYMODE;
			}
		}
#ifdef JOBS
		/* If it looks like user hit ^C to kill a job, pretend we got
		 * one too to break out of for loops, etc.  (at&t ksh does this
		 * even when not monitoring, but this doesn't make sense since
		 * a tty generated ^C goes to the whole process group)
		 */
		status = j->last_proc->status;
		if (Flag(FMONITOR) && j->state == PSIGNALLED &&
		    WIFSIGNALED(status) &&
		    (sigtraps[WTERMSIG(status)].flags & TF_TTY_INTR))
			trapsig(WTERMSIG(status));
#endif /* JOBS */
	}

	j_usrtime = j->usrtime;
	j_systime = j->systime;
	rv = j->status;

	if (!(flags & JW_ASYNCNOTIFY) &&
	    (!Flag(FMONITOR) || j->state != PSTOPPED)) {
		j_print(j, JP_SHORT, shl_out);
		shf_flush(shl_out);
	}
	if (j->state != PSTOPPED &&
	    (!Flag(FMONITOR) || !(flags & JW_ASYNCNOTIFY)))
		remove_job(j, where);

	return rv;
}
Пример #7
0
int
main(int argc, char **argv)
{
	int ch;
	unsigned long i;
	int foreground, preserve;
	int error, pstat, status;
	int killsig = SIGTERM;
	pid_t pgid, pid, cpid;
	double first_kill;
	double second_kill;
	bool timedout = false;
	bool do_second_kill = false;
	struct sigaction signals;
	int signums[] = {
		-1,
		SIGTERM,
		SIGINT,
		SIGHUP,
		SIGCHLD,
		SIGALRM,
		SIGQUIT,
	};

	foreground = preserve = 0;
	second_kill = 0;
	cpid = -1;
	pgid = -1;

	const struct option longopts[] = {
		{ "preserve-status", no_argument,       &preserve,    1 },
		{ "foreground",      no_argument,       &foreground,  1 },
		{ "kill-after",      required_argument, NULL,        'k'},
		{ "signal",          required_argument, NULL,        's'},
		{ "help",            no_argument,       NULL,        'h'},
		{ NULL,              0,                 NULL,         0 }
	};

	while ((ch = getopt_long(argc, argv, "+k:s:h", longopts, NULL)) != -1) {
		switch (ch) {
			case 'k':
				do_second_kill = true;
				second_kill = parse_duration(optarg);
				break;
			case 's':
				killsig = parse_signal(optarg);
				break;
			case 0:
				break;
			case 'h':
			default:
				usage();
				break;
		}
	}

	argc -= optind;
	argv += optind;

	if (argc < 2)
		usage();

	first_kill = parse_duration(argv[0]);
	argc--;
	argv++;

	if (!foreground) {
		pgid = setpgid(0,0);

		if (pgid == -1)
			err(EX_OSERR, "setpgid()");
	}

	memset(&signals, 0, sizeof(signals));
	sigemptyset(&signals.sa_mask);

	if (killsig != SIGKILL && killsig != SIGSTOP)
		signums[0] = killsig;

	for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i ++)
		sigaddset(&signals.sa_mask, signums[i]);

	signals.sa_handler = sig_handler;
	signals.sa_flags = SA_RESTART;

	for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i ++)
		if (signums[i] != -1 && signums[i] != 0 &&
		    sigaction(signums[i], &signals, NULL) == -1)
			err(EX_OSERR, "sigaction()");

	signal(SIGTTIN, SIG_IGN);
	signal(SIGTTOU, SIG_IGN);

	pid = fork();
	if (pid == -1)
		err(EX_OSERR, "fork()");
	else if (pid == 0) {
		/* child process */
		signal(SIGTTIN, SIG_DFL);
		signal(SIGTTOU, SIG_DFL);

		error = execvp(argv[0], argv);
		if (error == -1)
			err(EX_UNAVAILABLE, "exec()");
	}

	if (sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL) == -1)
		err(EX_OSERR, "sigprocmask()");

	/* parent continues here */
	set_interval(first_kill);

	for (;;) {
		sigemptyset(&signals.sa_mask);
		sigsuspend(&signals.sa_mask);

		if (sig_chld) {
			sig_chld = 0;
			while (((cpid = wait(&status)) < 0) && errno == EINTR)
				continue;

			if (cpid == pid) {
				pstat = status;
				break;
			}
		} else if (sig_alrm) {
			sig_alrm = 0;

			timedout = true;
			if (!foreground)
				killpg(pgid, killsig);
			else
				kill(pid, killsig);

			if (do_second_kill) {
				set_interval(second_kill);
				second_kill = 0;
				sig_ign = killsig;
				killsig = SIGKILL;
			} else
				break;

		} else if (sig_term) {
			if (!foreground)
				killpg(pgid, killsig);
			else
				kill(pid, sig_term);

			if (do_second_kill) {
				set_interval(second_kill);
				second_kill = 0;
				sig_ign = killsig;
				killsig = SIGKILL;
			} else
				break;
		}
	}

	while (cpid != pid  && wait(&pstat) == -1) {
		if (errno != EINTR)
			err(EX_OSERR, "waitpid()");
	}

	if (WEXITSTATUS(pstat))
		pstat = WEXITSTATUS(pstat);
	else if(WIFSIGNALED(pstat))
		pstat = 128 + WTERMSIG(pstat);

	if (timedout && !preserve)
		pstat = EXIT_TIMEOUT;

	return (pstat);
}
/*
 * 主要工作:
 * 主进程设置信号堵塞
 * 设置进程标题
 * 启动worker进程
 * 启动缓存索引重建(cache loader)进程及管理(Cache Manager)进程
 * 主进程循环处理信号
 * */
void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
    char              *title;
    u_char            *p;
    size_t             size;
    ngx_int_t          i;
    ngx_uint_t         n, sigio;
    sigset_t           set;
    struct itimerval   itv;
    ngx_uint_t         live;
    ngx_msec_t         delay;   /*保存的是等待工作进程退出的时间*/
    ngx_listening_t   *ls;
    ngx_core_conf_t   *ccf;

    /*将下列信号添加到信号集set中*/
    sigemptyset(&set);
    sigaddset(&set, SIGCHLD);
    sigaddset(&set, SIGALRM);
    sigaddset(&set, SIGIO);
    sigaddset(&set, SIGINT);
    sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));

    /*将信号集set覆盖为当前进程的信号集*/
    if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
     "sigprocmask() failed");
    }

    sigemptyset(&set);


    /*开始设置进程标题*/
    /*计算进程标题的总体长度*/
    size = sizeof(master_process);

    for (i = 0; i < ngx_argc; i++) {
        size += ngx_strlen(ngx_argv[i]) + 1;
    }

    title = ngx_pnalloc(cycle->pool, size);
    if (title == NULL) {
        /* fatal */
        exit(2);
    }

    p = ngx_cpymem(title, master_process, sizeof(master_process) - 1);
    for (i = 0; i < ngx_argc; i++) {
        *p++ = ' ';
        p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size);
    }

    /*设置进程标题*/
    ngx_setproctitle(title);

    /*获取核心模块上下文*/
    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);

    /*启动工作进程*/
    ngx_start_worker_processes(cycle, ccf->worker_processes,
                               NGX_PROCESS_RESPAWN);
    /*启动缓存索引重建进程,该进程在整个Nginx服务器运行过程中只存在很短的时间,主要用来遍历磁盘上的缓存数据,在内存中建立数据索引,提高Nginx服务器检索缓存的效率*/
    ngx_start_cache_manager_processes(cycle, 0);

    ngx_new_binary = 0;
    delay = 0;
    sigio = 0;
    live = 1;

    for ( ;; ) {
        if (delay) {
            /*等待工作进程退出的时间*/
            if (ngx_sigalrm) {
                sigio = 0;
                delay *= 2;
                ngx_sigalrm = 0;
            }

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "termination cycle: %M", delay);

            /*初始化一个定时器*/
            itv.it_interval.tv_sec = 0;
            itv.it_interval.tv_usec = 0;
            itv.it_value.tv_sec = delay / 1000;
            itv.it_value.tv_usec = (delay % 1000 ) * 1000;

            if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "setitimer() failed");
            }
        }

        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend");

        /*挂起进程,等待接收到信号,在不向主进程发送信号的情况下,该进程将一直挂起在这里等待*/
        sigsuspend(&set);

        /*更新缓冲时间*/
        ngx_time_update();

        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "wake up, sigio %i", sigio);

        /*如果有工作进程异常退出,则调用ngx_reap_children()重启该工作进程*/
        if (ngx_reap) {
            ngx_reap = 0;
            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");

            /*重启工作进程*/
            live = ngx_reap_children(cycle);
        }

        /*如果主进程接收到的是NGX_CMD_TERMINATE信号、SIGTERM信号、SIGINT信号(ngx_terminate=1)或者收到的是NGX_CMD_QUIT信号、SIGQUIT信号(ngx_quit=1),并且工作进程退出,则主进程调用ngx_master_process_exit()函数退出*/
        if (!live && (ngx_terminate || ngx_quit)) {
            ngx_master_process_exit(cycle);
        }

        /*处理SIGINT信号*/
        if (ngx_terminate) {
            if (delay == 0) {
                delay = 50;
            }

            if (sigio) {
                sigio--;
                continue;
            }

            /*包括两个管理内存索引的进程*/
            sigio = ccf->worker_processes + 2 /* cache processes */;

            /*超时1s,直接终止工作进程*/
            if (delay > 1000) {
                ngx_signal_worker_processes(cycle, SIGKILL);
            } else {
                /*工作进程正常退出*/
                ngx_signal_worker_processes(cycle,
                                       ngx_signal_value(NGX_TERMINATE_SIGNAL));
            }

            continue;
        }

        /*处理SIGQUIT信号*/
        if (ngx_quit) {
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));

            /*关闭所有的socket*/
            ls = cycle->listening.elts;
            for (n = 0; n < cycle->listening.nelts; n++) {
                if (ngx_close_socket(ls[n].fd) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                                  ngx_close_socket_n " %V failed",
                                  &ls[n].addr_text);
                }
            }
            cycle->listening.nelts = 0;

            continue;
        }

        /*处理SIGHUP信号*/
        if (ngx_reconfigure) {
            ngx_reconfigure = 0;

            /*热升级(平滑升级,不用停止服务)*/
            /*当ngx_new_binary=1时,说明主进程本身需要升级,但是不需要重新初始化Nginx配置,因此可以直接调用ngx_start_worker_processes()函数重启工作进程和缓存索引管理进程*/
            /*当ngx_new_binary!=1时,则说明时Nginx服务器配置改变,需要调用ngx_init_cycle()函数初始化Nginx配置,并按照新的配置启动工作进程和缓存索引管理进程,向之前的所有进程发送NGX_SHUTDOWN_SIGNAL信号,这样旧实现了Nginx服务器的平滑升级*/
            if (ngx_new_binary) {
                ngx_start_worker_processes(cycle, ccf->worker_processes,
                                           NGX_PROCESS_RESPAWN);
                ngx_start_cache_manager_processes(cycle, 0);
                ngx_noaccepting = 0;

                continue;
            }

            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");

            /*建立信的cycle结构*/
            cycle = ngx_init_cycle(cycle);
            if (cycle == NULL) {
                cycle = (ngx_cycle_t *) ngx_cycle;
                continue;
            }

            /*读取Nginx配置*/
            ngx_cycle = cycle;
            ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
                                                   ngx_core_module);
            /*创建工作进程*/
            ngx_start_worker_processes(cycle, ccf->worker_processes,
                                       NGX_PROCESS_JUST_RESPAWN);
            /*创建缓存管理进程*/
            ngx_start_cache_manager_processes(cycle, 1);

            /* allow new processes to start */
            ngx_msleep(100);

            live = 1;
            /*关闭旧的Nginx进程*/
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
        }

        /*重启工作进程*/
        /*只有一种情况可以将ngx_restart变量赋值为1,就是在调用ngx_reap_children()函数重启工作进程的时候,当主进程接收到NGX_NOACCEPT_SIGNAL信号(不再接收请求,退出工作进程)时,会设置全局变量ngx_noaccept为1,然后再Nginx初始化信号设置时会将全局变量ngx_noaccepting设置为1,于是在ngx_reap_children()函数中就会将ngx_restart变量设置为1,进而执行下面的if语句中的代码,重启工作进程和缓存索引管理进程*/
        if (ngx_restart) {
            ngx_restart = 0;
            /*启动工作进程*/
            ngx_start_worker_processes(cycle, ccf->worker_processes,
                                       NGX_PROCESS_RESPAWN);
            /*启动缓存索引管理进程刷新缓存索引*/
            ngx_start_cache_manager_processes(cycle, 0);
            live = 1;
        }

        /*处理SIGUSR1信号,该信号用于重新打开日志文件*/
        if (ngx_reopen) {
            ngx_reopen = 0;
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
            ngx_reopen_files(cycle, ccf->user);
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_REOPEN_SIGNAL));
        }

        /*处理SIGUSR2信号,热代码切换*/
        if (ngx_change_binary) {
            ngx_change_binary = 0;
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary");
            ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv);
        }

        /*处理NGX_NOACCEPT_SIGNAL信号*/
        if (ngx_noaccept) {
            ngx_noaccept = 0;
            ngx_noaccepting = 1;
            /*退出工作进程,不再接收网络请求*/
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
        }
    }
}
Пример #9
0
void producer( pid_t ch_pid, int argc, char * argv[] )
{
    /*******************************************
     * Define producer (parent) process
     *******************************************/
    printf("\tPRODUCER: pid = %d\n", getpid());

    struct sigaction action;
    action.sa_handler = SIG_IGN;
    sigaction(SIGUSR1, &action, NULL);

    /* Read input file */
    char    buffer[BUFSIZE];
    ssize_t count;
    int     fdin;

    /* validate arguments from program call */
    if ( argc !=2 )
    {
        printf( "Usage: %s  <input_filename>\n", argv[0] );
        exit(1);
    }

    /* validate input file */
    if ( (fdin = open(argv[1], O_RDONLY)) == -1 )
    {
        perror("Error opening the input file");
        exit(2);
    }

    /* enter while loop to process data from input file */
    sigset_t mask;
    sigemptyset ( &mask );
    while ( (count=read(fdin, buffer, BUFSIZE)) > 0 )
    {
        /* Copy data from local buffer into shared memory */
        memcpy( shmem_ptr->buf, buffer, count );
#ifdef DEBUG
            printf("PRODUCER: wrote %zu bytes to shared mem\n", count);
#endif

        /* Send signal to consumer */
#ifdef DEBUG
            printf("PRODUCER: signal Consumer that shared memory ready to read\n");
#endif
        send_rt_signal( ch_pid, SIGUSR1, (int)count );

        /* Suspend until signal received from consumer */
#ifdef DEBUG
        printf("PRODUCER: suspend until signal received from Consumer...\n");
#endif
        sigsuspend( &mask );  /* No signals are masked while waiting */
    }

    if ( count == -1 ) {
       perror ("Error reading input file");
       exit(4);
    }

    close(fdin);

    /* Send signal to consumer */
#ifdef DEBUG
    printf("PRODUCER: signal Consumer that Producer has reached EOF\n");
#endif
    send_rt_signal( ch_pid, SIGUSR1, -1 );

    /* Suspend until signal received from consumer */
#ifdef DEBUG
    printf("PRODUCER: suspend until signal received from Consumer...\n");
#endif
    sigsuspend( &mask );  /* No signals are masked while waiting */
}
Пример #10
0
int
main(int argc, char **argv) {
    int status;
    pid_t waited;
    char *device, *real_device, *physicalDevice = NULL;
    char *boot = NULL;
    shvarFile *ifcfg;
    sigset_t blockedsigs, unblockedsigs;
    int pppdPid = 0;
    int timeout = 30;
    char *temp;
    gboolean dying = FALSE;
    int sendsig;
    gboolean connectedOnce = FALSE;
    int maxfail = 0;		// MAXFAIL Patch <*****@*****.**>

    if (argc < 2) {
	fprintf (stderr, "usage: ppp-watch <interface-name> [boot]\n");
	exit(30);
    }

    if (strncmp(argv[1], "ifcfg-", 6) == 0) {
	device = argv[1] + 6;
    } else {
	device = argv[1];
    }

    detach(device); /* Prepare a child process to monitor pppd.  When we
		       return, we'll be in the child. */

    if ((argc > 2) && (strcmp("boot", argv[2]) == 0)) {
	boot = argv[2];
    }

    ifcfg = shvarfilesGet(device);
    if (ifcfg == NULL)
	failureExit(28);

    real_device = svGetValue(ifcfg, "DEVICE");
    if (real_device == NULL)
	real_device = device;

    doPidFile(real_device);

    /* We'll want to know which signal interrupted our sleep below, so
     * attach a signal handler to these. */
    set_signal(SIGTERM, signal_tracker);
    set_signal(SIGINT, signal_tracker);
    set_signal(SIGHUP, signal_tracker);
    set_signal(SIGIO, signal_tracker);
    set_signal(SIGCHLD, signal_tracker);

    /* We time out only if we're being run at boot-time. */
    if (boot) {
	temp = svGetValue(ifcfg, "BOOTTIMEOUT");
	if (temp) {
	    timeout = atoi(temp);
	    if (timeout < 1) timeout = 1;
	    free(temp);
	} else {
	    timeout = 30;
	}
	set_signal(SIGALRM, signal_tracker);
	alarm(timeout);
    }

    /* Register us to get a signal when something changes. Yes, that's vague. */
    fork_exec(TRUE, "/sbin/netreport", NULL, NULL, NULL);

    /* Reset theSigchld, which should have been triggered by netreport. */
    theSigchld = 0;

    /* We don't set up the procmask until after we have received the netreport
     * signal.  Do so now. */
    sigemptyset(&blockedsigs);
    sigaddset(&blockedsigs, SIGTERM);
    sigaddset(&blockedsigs, SIGINT);
    sigaddset(&blockedsigs, SIGHUP);
    sigaddset(&blockedsigs, SIGIO);
    sigaddset(&blockedsigs, SIGCHLD);
    if (boot) {
	sigaddset(&blockedsigs, SIGALRM);
    }
    sigprocmask(SIG_BLOCK, &blockedsigs, NULL);

    sigfillset(&unblockedsigs);
    sigdelset(&unblockedsigs, SIGTERM);
    sigdelset(&unblockedsigs, SIGINT);
    sigdelset(&unblockedsigs, SIGHUP);
    sigdelset(&unblockedsigs, SIGIO);
    sigdelset(&unblockedsigs, SIGCHLD);
    if (boot) {
	sigdelset(&unblockedsigs, SIGALRM);
    }
    sigprocmask(SIG_UNBLOCK, &unblockedsigs, NULL);

    /* Initialize the retry timeout using the RETRYTIMEOUT setting. */
    temp = svGetValue(ifcfg, "RETRYTIMEOUT");
    if (temp) {
	timeout = atoi(temp);
	free(temp);
    } else {
	timeout = 30;
    }

    /* Start trying to bring the interface up. */
    fork_exec(FALSE, IFUP_PPP, "daemon", device, boot);

    while (TRUE) {
	/* Wait for a signal. */
	if (!theSigterm &&
	    !theSigint &&
	    !theSighup &&
	    !theSigio &&
	    !theSigchld &&
	    !theSigalrm) {
	    sigsuspend(&unblockedsigs);
	}

	/* If we got SIGTERM or SIGINT, give up and hang up. */
	if (theSigterm || theSigint) {
	    theSigterm = theSigint = 0;

	    /* If we've already tried to exit this way, use SIGKILL instead
	     * of SIGTERM, because pppd's just being stubborn. */
	    if (dying) {
		sendsig = SIGKILL;
	    } else {
		sendsig = SIGTERM;
	    }
	    dying = TRUE;

	    /* Get the pid of our child pppd. */
	    pppLogicalToPhysical(&pppdPid, device, NULL);

	    /* We don't know what our child pid is.  This is very confusing. */
	    if (!pppdPid) {
		failureExit(35);
	    }

	    /* Die, pppd, die. */
	    kill(pppdPid, sendsig);
	    if (sendsig == SIGKILL) {
		kill(-pppdPid, SIGTERM); /* Give it a chance to die nicely, then
					    kill its whole process group. */
		usleep(2500000);
		kill(-pppdPid, sendsig);
		hangup(ifcfg);
		failureExit(32);
	    }
	}

	/* If we got SIGHUP, reload and redial. */
	if (theSighup) {
	    theSighup = 0;

	    /* Free and reload the configuration structure. */
	    if (ifcfg->parent)
		svCloseFile(ifcfg->parent);
	    svCloseFile(ifcfg);
	    ifcfg = shvarfilesGet(device);

	    /* Get the PID of our child pppd. */
	    pppLogicalToPhysical(&pppdPid, device, NULL);
	    kill(pppdPid, SIGTERM);

	    /* We'll redial when the SIGCHLD arrives, even if PERSIST is
	     * not set (the latter handled by clearing the "we've connected
	     * at least once" flag). */
	    connectedOnce = FALSE;

 	    /* We don't want to delay before redialing, either, so cut
	     * the retry timeout to zero. */
	    timeout = 0;
	}

	/* If we got a SIGIO (from netreport, presumably), check if the
	 * interface is up and return zero (via our parent) if it is. */
	if (theSigio) {
	    theSigio = 0;

	    pppLogicalToPhysical(NULL, device, &physicalDevice);
	    if (physicalDevice) {
		if (interfaceIsUp(physicalDevice)) {
		    /* The interface is up, so report a success to a parent if
		     * we have one.  Any errors after this we just swallow. */
		    relay_exitcode(0);
		    connectedOnce = TRUE;
		    alarm(0);
		}
		free(physicalDevice);
	    }
	}

	/* If we got a SIGCHLD, then pppd died (possibly because we killed it),
	 * and we need to restart it after timeout seconds. */
	if (theSigchld) {
	    theSigchld = 0;

	    /* Find its pid, which is also its process group ID. */
	    waited = waitpid(-1, &status, 0);
	    if (waited == -1) {
		continue;
	    }

	    /* Now, we need to kill any children of pppd still in pppd's
	     * process group, in case they are hanging around.
	     * pppd is dead (we just waited for it) but there is no
	     * guarantee that its children are dead, and they will
	     * hold the modem if we do not get rid of them.
	     * We have kept the old pid/pgrp around in pppdPid.  */
	    if (pppdPid) {
		kill(-pppdPid, SIGTERM); /* give it a chance to die nicely */
		usleep(2500000);
		kill(-pppdPid, SIGKILL);
		hangup(ifcfg);
	    }
	    pppdPid = 0;

	    /* Bail if the child exitted abnormally or we were already
	     * signalled to kill it. */
	    if (!WIFEXITED(status)) {
		failureExit(29);
	    }
	    if (dying) {
		failureExit(WEXITSTATUS(status));
	    }

	    /* Error conditions from which we do not expect to recover
	     * without user intervention -- do not fill up the logs.  */
	    switch (WEXITSTATUS(status)) {
	    case 1: case 2: case 3: case 4: case 6:
	    case 7: case 9: case 14: case 17:
		failureExit(WEXITSTATUS(status));
		break;
	    default:
		break;
	    }

            /* PGB 08/20/02: We no longer retry connecting MAXFAIL
	       times on a failed connect script unless RETRYCONNECT is
	       true. */
	    if ((WEXITSTATUS(status) == 8) &&
		!svTrueValue(ifcfg, "RETRYCONNECT", FALSE)) {
                failureExit(WEXITSTATUS(status));
            }

	    /* If we've never connected, or PERSIST is set, dial again, up
	     * to MAXFAIL times. */
	    if ((WEXITSTATUS(status) == 8) ||
	        !connectedOnce ||
		svTrueValue(ifcfg, "PERSIST", FALSE)) {
		/* If we've been connected (i.e., if we didn't force a redial,
		 * but the connection went down) wait for DISCONNECTTIMEOUT
		 * seconds before redialing. */
		if (connectedOnce) {
		    connectedOnce = FALSE;
		    temp = svGetValue(ifcfg, "DISCONNECTTIMEOUT");
		    if (temp) {
			timeout = atoi(temp);
			free(temp);
		    } else {
			timeout = 2;
		    }
		}
		sigprocmask(SIG_UNBLOCK, &blockedsigs, NULL);
		sleep(timeout);
		sigprocmask(SIG_BLOCK, &blockedsigs, NULL);
		if (!theSigterm &&
		    !theSigint &&
		    !theSighup &&
		    !theSigio &&
		    !theSigchld &&
		    !theSigalrm) {
		    fork_exec(FALSE, IFUP_PPP, "daemon", device, boot);
		}
		/* Reinitialize the retry timeout. */
		temp = svGetValue(ifcfg, "RETRYTIMEOUT");
		if (temp) {
		    timeout = atoi(temp);
		    free(temp);
		} else {
		    timeout = 30;
		}
// Scott Sharkey <*****@*****.**>
// MAXFAIL Patch...
		temp = svGetValue(ifcfg, "MAXFAIL");
		if (temp) {
		    maxfail = atoi(temp);
		    free(temp);
		} else {
		    maxfail = 0;
		}
		if ( maxfail != 0 ) {
		    dialCount++;
		    if ( dialCount >= maxfail )
			failureExit(WEXITSTATUS(status));
		} 
	    } else {
		failureExit(WEXITSTATUS(status));
	    }
	}

	/* We timed out, and we're running at boot-time. */
	if (theSigalrm) {
	    failureExit(34);
	}
    }
}
Пример #11
0
APR_DECLARE(apr_status_t) apr_signal_thread(int(*signal_handler)(int signum))
{
    sigset_t sig_mask;
#if APR_HAVE_SIGWAIT
    int (*sig_func)(int signum) = (int (*)(int))signal_handler;
#endif

    /* This thread will be the one responsible for handling signals */
    sigfillset(&sig_mask);

    /* On certain platforms, sigwait() returns EINVAL if any of various
     * unblockable signals are included in the mask.  This was first 
     * observed on AIX and Tru64.
     */
#ifdef SIGKILL
    sigdelset(&sig_mask, SIGKILL);
#endif
#ifdef SIGSTOP
    sigdelset(&sig_mask, SIGSTOP);
#endif
#ifdef SIGCONT
    sigdelset(&sig_mask, SIGCONT);
#endif
#ifdef SIGWAITING
    sigdelset(&sig_mask, SIGWAITING);
#endif

    /* no synchronous signals should be in the mask passed to sigwait() */
    remove_sync_sigs(&sig_mask);

    /* On AIX (4.3.3, at least), sigwait() won't wake up if the high-
     * order bit of the second word of flags is turned on.  sigdelset()
     * returns an error when trying to turn this off, so we'll turn it
     * off manually.
     *
     * Note that the private fields differ between 32-bit and 64-bit
     * and even between _ALL_SOURCE and !_ALL_SOURCE.  Except that on
     * AIX 4.3 32-bit builds and 64-bit builds use the same definition.
     *
     * Applicable AIX fixes such that this is no longer needed:
     *
     * APAR IY23096 for AIX 51B, fix included in AIX 51C, and
     * APAR IY24162 for 43X.
     */
#if defined(_AIX)
#if defined(__64BIT__) && defined(_AIXVERSION_510)
#ifdef _ALL_SOURCE
        sig_mask.ss_set[3] &= 0x7FFFFFFF;
#else /* not _ALL_SOURCE */
        sig_mask.__ss_set[3] &= 0x7FFFFFFF;
#endif
#else /* not 64-bit build, or 64-bit build on 4.3 */
#ifdef _ALL_SOURCE
        sig_mask.hisigs &= 0x7FFFFFFF;
#else /* not _ALL_SOURCE */
        sig_mask.__hisigs &= 0x7FFFFFFF;
#endif
#endif
#endif /* _AIX */

    while (1) {
#if APR_HAVE_SIGWAIT
        int signal_received;

        if (apr_sigwait(&sig_mask, &signal_received) != 0)
        {
            /* handle sigwait() error here */
        }
        
        if (sig_func(signal_received) == 1) {
            return APR_SUCCESS;
        }
#elif HAVE_SIGSUSPEND
	sigsuspend(&sig_mask);
#else
#error No apr_sigwait() and no sigsuspend()
#endif
    }
}
Пример #12
0
static void
suspend_thread (SgenThreadInfo *info, void *context)
{
	int stop_count;
#ifndef USE_MONO_CTX
	gpointer regs [ARCH_NUM_REGS];
#endif
	MonoContext ctx;
	gpointer stack_start;

	info->client_info.stopped_domain = mono_domain_get ();
	info->client_info.signal = 0;
	stop_count = sgen_global_stop_count;
	/* duplicate signal */
	if (0 && info->client_info.stop_count == stop_count)
		return;

#ifdef USE_MONO_CTX
	if (context) {
		mono_sigctx_to_monoctx (context, &ctx);
		info->client_info.stopped_ip = MONO_CONTEXT_GET_IP (&ctx);
		stack_start = (((guint8 *) MONO_CONTEXT_GET_SP (&ctx)) - REDZONE_SIZE);
	} else {
		info->client_info.stopped_ip = NULL;
		stack_start = NULL;
	}
#else
	info->client_info.stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL;
	stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL;
#endif

	/* If stack_start is not within the limits, then don't set it
	   in info and we will be restarted. */
	if (stack_start >= info->client_info.stack_start_limit && stack_start <= info->client_info.stack_end) {
		info->client_info.stack_start = stack_start;

#ifdef USE_MONO_CTX
		if (context) {
			memcpy (&info->client_info.ctx, &ctx, sizeof (MonoContext));
		} else {
			memset (&info->client_info.ctx, 0, sizeof (MonoContext));
		}
#else
		if (context) {
			ARCH_COPY_SIGCTX_REGS (regs, context);
			memcpy (&info->client_info.regs, regs, sizeof (info->client_info.regs));
		} else {
			memset (&info->client_info.regs, 0, sizeof (info->client_info.regs));
		}
#endif
	} else {
		g_assert (!info->client_info.stack_start);
	}

	/* Notify the JIT */
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->client_info.runtime_data, context, NULL);

	SGEN_LOG (4, "Posting suspend_ack_semaphore for suspend from %p %p", info, (gpointer) (gsize) mono_native_thread_id_get ());

	/*
	Block the restart signal. 
	We need to block the restart signal while posting to the suspend_ack semaphore or we race to sigsuspend,
	which might miss the signal and get stuck.
	*/
	pthread_sigmask (SIG_BLOCK, &suspend_ack_signal_mask, NULL);

	/* notify the waiting thread */
	SGEN_SEMAPHORE_POST (suspend_ack_semaphore_ptr);
	info->client_info.stop_count = stop_count;

	/* wait until we receive the restart signal */
	do {
		info->client_info.signal = 0;
		sigsuspend (&suspend_signal_mask);
	} while (info->client_info.signal != restart_signal_num);

	/* Unblock the restart signal. */
	pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL);

	SGEN_LOG (4, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer) (gsize) mono_native_thread_id_get ());
	/* notify the waiting thread */
	SGEN_SEMAPHORE_POST (suspend_ack_semaphore_ptr);
}
Пример #13
0
int
main(int argc, char **argv)
{
	char buf[1024], *cp, c;
	int error, desc, rv;
	long scval;
	sigset_t ss;
	struct sigaction sa;
	void *region;
	size_t i, psize;

#ifndef _POSIX_SHARED_MEMORY_OBJECTS
	printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n");
#else
	printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n", 
	       (long)_POSIX_SHARED_MEMORY_OBJECTS - 0);
	if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1)
		printf("***Indicates this feature may be unsupported!\n");
#endif
	errno = 0;
	scval = sysconf(_SC_SHARED_MEMORY_OBJECTS);
	if (scval == -1 && errno != 0) {
		err(1, "sysconf(_SC_SHARED_MEMORY_OBJECTS)");
	} else {
		printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n",
		       scval);
		if (scval == -1)
			printf("***Indicates this feature is unsupported!\n");
	}

	errno = 0;
	scval = sysconf(_SC_PAGESIZE);
	if (scval == -1 && errno != 0) {
		err(1, "sysconf(_SC_PAGESIZE)");
	} else if (scval <= 0 || (size_t)psize != psize) {
		warnx("bogus return from sysconf(_SC_PAGESIZE): %ld",
		      scval);
		psize = 4096;
	} else {
		printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval);
		psize = scval;
	}

	argc--, argv++;

	if (*argv) {
		strncat(buf, *argv, (sizeof buf) - 1);
		desc = shm_open(buf, O_EXCL | O_CREAT | O_RDWR, 0600);
	} else {
		do {
			/*
			 * Can't use mkstemp for obvious reasons...
			 */
			strcpy(buf, "/tmp/shmtest.XXXXXXXXXXXX");
			mktemp(buf);
			desc = shm_open(buf, O_EXCL | O_CREAT | O_RDWR, 0600);
		} while (desc < 0 && errno == EEXIST);
	}

	if (desc < 0)
		err(1, "shm_open");

	if (shm_unlink(buf) < 0)
		err(1, "shm_unlink");

	if (ftruncate(desc, (off_t)psize) < 0)
		err(1, "ftruncate");

	region = mmap((void *)0, psize, PROT_READ | PROT_WRITE, MAP_SHARED,
		      desc, (off_t)0);
	if (region == MAP_FAILED)
		err(1, "mmap");
	memset(region, '\377', psize);

	sa.sa_flags = 0;
	sa.sa_handler = ignoreit;
	sigemptyset(&sa.sa_mask);
	if (sigaction(SIGUSR1, &sa, (struct sigaction *)0) < 0)
		err(1, "sigaction");

	sigemptyset(&ss);
	sigaddset(&ss, SIGUSR1);
	if (sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) < 0)
		err(1, "sigprocmask");

	rv = fork();
	if (rv < 0) {
		err(1, "fork");
	} else if (rv == 0) {
		sigemptyset(&ss);
		sigsuspend(&ss);

		for (cp = region; cp < (char *)region + psize; cp++) {
			if (*cp != '\151')
				_exit(1);
		}
		if (lseek(desc, 0, SEEK_SET) == -1)
			_exit(1);
		for (i = 0; i < psize; i++) {
			error = read(desc, &c, 1);
			if (c != '\151')
				_exit(1);
		}
		_exit(0);
	} else {
		int status;

		memset(region, '\151', psize - 2);
		error = pwrite(desc, region, 2, psize - 2);
		if (error != 2) {
			if (error >= 0)
				errx(1, "short write %d", error);
			else
				err(1, "shmfd write");
		}
		kill(rv, SIGUSR1);
		waitpid(rv, &status, 0);

		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
			printf("Functionality test successful\n");
			exit(0);
		} else if (WIFEXITED(status)) {
			printf("Child process exited with status %d\n",
			       WEXITSTATUS(status));
		} else {
			printf("Child process terminated with %s\n",
			       strsignal(WTERMSIG(status)));
		}
	}
	exit(1);
}
Пример #14
0
/* 
 * eval - Evaluate the command line that the user has just typed in
 * 
 * If the user has requested a built-in command (quit, jobs, bg or fg)
 * then execute it immediately. Otherwise, fork a child process and
 * run the job in the context of the child. If the job is running in
 * the foreground, wait for it to terminate and then return.  Note:
 * each child process must have a unique process group ID so that our
 * background children don't receive SIGINT (SIGTSTP) from the kernel
 * when we type ctrl-c (ctrl-z) at the keyboard.  
 */
void 
eval(char *cmdline) 
{
    int bg;              /* should the job run in bg or fg? */
    struct cmdline_tokens tok;

    int temp;
    pid_t pid;

    // variables to be used for blocking and unblocking signals
    sigset_t sigs;
    sigset_t sigmask;
    sigset_t wmask;
    sigemptyset(&sigmask);

    int jobID;
    struct job_t *new_job;

    /* Parse command line */
    bg = parseline(cmdline, &tok); 

    if (bg == -1) /* parsing error */
        return;

    if (tok.argv[0] == NULL) /* ignore empty lines */
        return;

    // If user enters builtin command quit
    // normally exits
    else if(tok.builtins == BUILTIN_QUIT)
      exit(0);
    
    // If user enters builtin command jobs
    // Lists all the current running and stopped jobs
    else if(tok.builtins == BUILTIN_JOBS)
    {
      if(tok.outfile == NULL)
	listjobs(job_list,1);
      else
      {
	temp = open(tok.outfile,O_WRONLY);
	listjobs(job_list,temp);
      }
    }

    // If user did not enter any built in commands
    else if(tok.builtins == BUILTIN_NONE)
    {

      //initialize signals and block
      sigemptyset(&sigs);
      sigaddset(&sigs, SIGINT);
      sigaddset(&sigs, SIGTSTP);
      sigaddset(&sigs, SIGCHLD);
      sigprocmask(SIG_BLOCK, &sigs, NULL);

      // I/O redirection
      if((pid = fork()) == 0)
      {
	if(tok.infile != NULL)
	  dup2(open(tok.infile, O_RDONLY), 0);
	if(tok.outfile != NULL)
	  dup2(open(tok.outfile, O_WRONLY), 0);
	
	setpgid(0, 0);
	sigprocmask(SIG_UNBLOCK, &sigs, NULL);
	
	if(execve(tok.argv[0], tok.argv, environ) < 0) //execute user command
	{
	  printf("%s: Command not found. \n", tok.argv[0]);
	  exit(0);
	}
      }

      if(!addjob(job_list, pid, bg ? BG : FG, cmdline))
        return;

      if(!bg)
	while(fgpid(job_list)) // wait for foreground job to finish
	  sigsuspend(&sigmask);
      else
	printf("[%d] (%d) %s\n",pid2jid(pid),pid,cmdline);

      sigprocmask(SIG_UNBLOCK,&sigs,NULL);
    }

    // If user enters builtin command FG (Foreground)
    if(tok.builtins == BUILTIN_FG)
    {
      jobID = atoi(tok.argv[1] + 1);
      new_job = getjobjid(job_list, jobID);
      kill(-new_job->pid, SIGCONT);

      new_job->state = FG;
      while (fgpid(job_list))
        sigsuspend(&wmask);
      
    }

    // If user enters builtin command FG (Foreground)
    else if(tok.builtins == BUILTIN_BG)
    {
      jobID = atoi(tok.argv[1] + 1);
      new_job = getjobjid(job_list, jobID);
      kill(-new_job->pid, SIGCONT);

      new_job->state = BG;
      printf("[%d] (%d) %s\n", jobID, new_job->pid, new_job->cmdline);
    }

    return;
}
Пример #15
0
/* 
 * eval - Evaluate the command line that the user has just typed in
 * 
 * If the user has requested a built-in command (quit, jobs, bg or fg)
 * then execute it immediately. Otherwise, fork a child process and
 * run the job in the context of the child. If the job is running in
 * the foreground, wait for it to terminate and then return.  Note:
 * each child process must have a unique process group ID so that our
 * background children don't receive SIGINT (SIGTSTP) from the kernel
 * when we type ctrl-c (ctrl-z) at the keyboard.  
 */
void 
eval(char *cmdline) 
{
    int bg;              /* should the job run in bg or fg? */
    struct cmdline_tokens tok;

    int fd_in = STDIN_FILENO;
    int fd_out = STDOUT_FILENO;
    //int status;
    sigset_t mask, prev_mask;
    struct job_t *job;
    pid_t pid;


    /* Parse command line */
    bg = parseline(cmdline, &tok); 

    if (bg == -1) /* parsing error */
        return;
    if (tok.argv[0] == NULL) /* ignore empty lines */
        return;

    //Handle IO redirection
    if(tok.infile != NULL ) {
        if( (fd_in = open(tok.infile,O_RDONLY, 0)) < 0 )
            app_error("cannot open input file");
    }

    if(tok.outfile != NULL ) {
        if( (fd_out = open(tok.outfile,O_WRONLY|O_CREAT, 0644)) < 0 )
            app_error("cannot open output file");
    }

    switch(tok.builtins) {
    case BUILTIN_QUIT:
        exit(0);
        break;
    case BUILTIN_JOBS:
        listjobs(job_list,fd_out);
        break;
    case BUILTIN_BG:
        if(tok.argc < 2)
            app_error("lack of argument: PID or %%jobid");
        if(tok.argv[1][0] == '%')
            job = getjobjid(job_list,atoi(tok.argv[1]+1));
        else
            job = getjobpid(job_list,atoi(tok.argv[1]));

        if( !job )
            app_error("no such process or job");

        //Set job state to BG and send SIGCONT to its process group
        job->state = BG;
        printf("[%d] (%d) %s\n", job->jid, job->pid, job->cmdline);
        kill(-job->pid,SIGCONT);
        break;
    case BUILTIN_FG:
        if(tok.argc < 2)
            app_error("lack of argument: PID or %%jobid");
        if(tok.argv[1][0] == '%')
            job = getjobjid(job_list,atoi(tok.argv[1]+1));
        else
            job = getjobpid(job_list,atoi(tok.argv[1]));

        if( !job )
            app_error("no such processs or job");

        //Set job state to FG, send SIGCONT to its process, bring it to the front
        job->state = FG;
        kill(-job->pid, SIGCONT);
        
        //wait the fg process by a sigsuspend
        sigemptyset(&mask);
        if(!bg)
            while( fgpid(job_list) > 0 )
                sigsuspend(&mask);

        break;
    case BUILTIN_NONE:
        //Block SIGINT, SIGTSTP, SIGCHLD to avoid race 
        sigemptyset(&mask);
        sigaddset(&mask, SIGINT);
        sigaddset(&mask, SIGCHLD);
        sigaddset(&mask, SIGTSTP);
        sigprocmask(SIG_BLOCK, &mask, &prev_mask);

        //Child
        if((pid = fork()) == 0) {
            //Make SIGINT only send to tsh
            setpgid(0, 0);
            sigprocmask(SIG_SETMASK, &prev_mask, NULL);

            //Restore the signals ignored by shell
            Signal(SIGTTIN, SIG_DFL);
            Signal(SIGTTOU, SIG_DFL);

            //IO redirection
            if( tok.infile != NULL )
                if( dup2(fd_in, STDIN_FILENO) < 0 )
                    app_error("IO redirection error");

            if( tok.outfile != NULL )
                if( dup2(fd_out, STDOUT_FILENO) < 0 )
                    app_error("IO redirection error");


            if(execve(tok.argv[0], tok.argv, environ) <  0 ) {
                printf("%s: Command not found\n", tok.argv[0]);
                exit(1);
            }
        }

        //Parent
        //Background job
        if(bg == 1) {
            addjob(job_list,pid, BG, cmdline);
            printf("[%d] (%d) %s\n", pid2jid(pid), pid, cmdline);
        }
        else 
            addjob(job_list,pid, FG, cmdline);

        //wait the fg process by a sigsuspend, all signal is handled during waiting time
        sigemptyset(&mask);
        if(!bg)
            while( fgpid(job_list) > 0 )
                sigsuspend(&mask);

        sigprocmask(SIG_SETMASK, &prev_mask, NULL);
        break;
    default:
        app_error("undefined builtin job");
    }

    //Close IO files
    if(fd_in != STDIN_FILENO )
        close(fd_in);
    if(fd_out != STDOUT_FILENO )
        close(fd_out);

    return;
}
Пример #16
0
void consumer( void )
{
    /*******************************************
     * Define consumer (child) process
     *******************************************/
    printf("\tCONSUMER: pid = %d\n", getpid());
    consumer_done = 0;

    struct sigaction action;
    action.sa_handler = SIG_IGN;
    sigaction(SIGUSR2, &action, NULL);

    /*  Reuse key set in main to get the segment id of the
        segment that the parent process created. The size parameter is set
        to zero, and the flag to IPC_ALLOC, indicating that the segment is
        not being created here, it already exists
    */
    shmem_id = shmget (key, 0, 0);
    if (shmem_id == -1)
    {
        perror("child shmget failed");
        exit(1);
    }
#ifdef DEBUG
        printf("Consumer: Got shmem id = %d\n", shmem_id);
#endif

    /* Now attach this segment into the child address space */
        shmem_ptr = shmat (shmem_id, (void *) NULL, flag);
    if (shmem_ptr == (void *) -1)
    {
        perror("child shmat failed");
        exit(2);
    }
#ifdef DEBUG
        printf("Consumer: Got ptr = %p\n", shmem_ptr);
#endif


    /* open output file */
    mode_t  perms;
    perms = 0740;
    if ( (fdout = open ("output", (O_WRONLY | O_CREAT), perms)) == -1 )
    {
        perror("Error in creating output file");
        exit(3);
    }


    /* Suspend until signal received from producer */
    sigset_t mask;
    sigemptyset ( &mask );

    while ( consumer_done == 0 )
    {
#ifdef DEBUG
        printf("CONSUMER: suspend until signal received from Producer...\n");
#endif
        sigsuspend( &mask );  /* No signals are masked while waiting */
    }


    /* close the file */
    close(fdout);

    /* compute metrics from data transfer */
    struct timespec ts_now;
    float           d_xfr_t;

    clock_gettime( CLOCK_MONOTONIC, &ts_now );
    d_xfr_t = diff_time( &(shmem_ptr->ts), &ts_now );
    printf("\tData transfer completed in %f ms\n", d_xfr_t);

    /* done with the program, so detach the shared segment */
    shmdt( (void *)shmem_ptr);

    /* send signal to producer to indicate transfer complete */
#ifdef DEBUG
    printf("CONSUMER: signal Producer that data transfer is complete\n");
#endif
    send_rt_signal( getppid(), SIGUSR2, 0 );
}
Пример #17
0
/*
 * Print a running summary of interface statistics.
 * Repeat display every interval seconds, showing statistics
 * collected over that interval.  Assumes that interval is non-zero.
 * First line printed is cumulative.
 */
static void
intpr(void)
{
    int line = 0;
    sigset_t oldmask, mask;
    char *bunit;
    int ratef = 0;
    struct ppp_stats cur, old;
    struct ppp_comp_stats ccs, ocs;

    memset(&old, 0, sizeof(old));
    memset(&ocs, 0, sizeof(ocs));

    while (1) {
	get_ppp_stats(&cur);
	if (zflag || rflag)
	    get_ppp_cstats(&ccs);

	signal(SIGALRM, catchalarm);
	signalled = 0;
	alarm(interval);

	if ((line % 20) == 0) {
	    if (zflag) {
		printf("IN:  COMPRESSED  INCOMPRESSIBLE   COMP | ");
		printf("OUT: COMPRESSED  INCOMPRESSIBLE   COMP\n");
		bunit = dflag? "KB/S": "BYTE";
		printf("    %s   PACK     %s   PACK  RATIO | ", bunit, bunit);
		printf("    %s   PACK     %s   PACK  RATIO", bunit, bunit);
	    } else {
		printf("%8.8s %6.6s %6.6s",
		       "IN", "PACK", "VJCOMP");

		if (!rflag)
		    printf(" %6.6s %6.6s", "VJUNC", "VJERR");
		if (vflag)
		    printf(" %6.6s %6.6s", "VJTOSS", "NON-VJ");
		if (rflag)
		    printf(" %6.6s %6.6s", "RATIO", "UBYTE");
		printf("  | %8.8s %6.6s %6.6s",
		       "OUT", "PACK", "VJCOMP");

		if (!rflag)
		    printf(" %6.6s %6.6s", "VJUNC", "NON-VJ");
		if (vflag)
		    printf(" %6.6s %6.6s", "VJSRCH", "VJMISS");
		if (rflag)
		    printf(" %6.6s %6.6s", "RATIO", "UBYTE");
	    }
	    putchar('\n');
	}

	if (zflag) {
	    if (ratef) {
		printf("%8.3f %6u %8.3f %6u %6.2f",
		       KBPS(W(d.comp_bytes)),
		       W(d.comp_packets),
		       KBPS(W(d.inc_bytes)),
		       W(d.inc_packets),
		       ccs.d.ratio / 256.0);
		printf(" | %8.3f %6u %8.3f %6u %6.2f",
		       KBPS(W(c.comp_bytes)),
		       W(c.comp_packets),
		       KBPS(W(c.inc_bytes)),
		       W(c.inc_packets),
		       ccs.c.ratio / 256.0);
	    } else {
		printf("%8u %6u %8u %6u %6.2f",
		       W(d.comp_bytes),
		       W(d.comp_packets),
		       W(d.inc_bytes),
		       W(d.inc_packets),
		       ccs.d.ratio / 256.0);
		printf(" | %8u %6u %8u %6u %6.2f",
		       W(c.comp_bytes),
		       W(c.comp_packets),
		       W(c.inc_bytes),
		       W(c.inc_packets),
		       ccs.c.ratio / 256.0);
	    }
	
	} else {
	    if (ratef)
		printf("%8.3f", KBPS(V(p.ppp_ibytes)));
	    else
		printf("%8u", V(p.ppp_ibytes));
	    printf(" %6u %6u",
		   V(p.ppp_ipackets),
		   V(vj.vjs_compressedin));
	    if (!rflag)
		printf(" %6u %6u",
		       V(vj.vjs_uncompressedin),
		       V(vj.vjs_errorin));
	    if (vflag)
		printf(" %6u %6u",
		       V(vj.vjs_tossed),
		       V(p.ppp_ipackets) - V(vj.vjs_compressedin)
		       - V(vj.vjs_uncompressedin) - V(vj.vjs_errorin));
	    if (rflag) {
		printf(" %6.2f ", CRATE(d));
		if (ratef)
		    printf("%6.2f", KBPS(W(d.unc_bytes)));
		else
		    printf("%6u", W(d.unc_bytes));
	    }
	    if (ratef)
		printf("  | %8.3f", KBPS(V(p.ppp_obytes)));
	    else
		printf("  | %8u", V(p.ppp_obytes));
	    printf(" %6u %6u",
		   V(p.ppp_opackets),
		   V(vj.vjs_compressed));
	    if (!rflag)
		printf(" %6u %6u",
		       V(vj.vjs_packets) - V(vj.vjs_compressed),
		       V(p.ppp_opackets) - V(vj.vjs_packets));
	    if (vflag)
		printf(" %6u %6u",
		       V(vj.vjs_searches),
		       V(vj.vjs_misses));
	    if (rflag) {
		printf(" %6.2f ", CRATE(c));
		if (ratef)
		    printf("%6.2f", KBPS(W(c.unc_bytes)));
		else
		    printf("%6u", W(c.unc_bytes));
	    }

	}

	putchar('\n');
	fflush(stdout);
	line++;

	count--;
	if (!infinite && !count)
	    break;

	sigemptyset(&mask);
	sigaddset(&mask, SIGALRM);
	sigprocmask(SIG_BLOCK, &mask, &oldmask);
	if (!signalled) {
	    sigemptyset(&mask);
	    sigsuspend(&mask);
	}
	sigprocmask(SIG_SETMASK, &oldmask, NULL);
	signalled = 0;
	alarm(interval);

	if (!aflag) {
	    old = cur;
	    ocs = ccs;
	    ratef = dflag;
	}
    }
}
Пример #18
0
int main(int argc, char *argv[]) {
    void (*sig_old)(int);
    sigset_t block_sig;
    sigset_t block_sig_;
    sigset_t old_sig;
    sigset_t test_sig;

    printf("My pid is: %d\n",getpid());

    // imposta i signal handler
    sig_old=signal(SIGALRM,sig_user_alarm);
    signal(SIGUSR1,sig_user_print);
    signal(SIGUSR2,sig_user_print_);

    printf("Setting alarm\n");
    // imposta l'allarme
    alarm(30);

    // inizializzazione della maschera di sblocco
    sigemptyset(&block_sig);
    // sospenditi in attesa si SIGALRM (se arriva un altro segnale
    // prima di SIGALRM, ad esempio SIGUSR1 o SIGUSR2, il programma
    // andra' avanti)
    sigsuspend(&block_sig);

    // stampa il valore di boom
    printf("Boom=%d\n",boom);
    printf("Something else\n");

    // reimposta l'handler originario
    signal(SIGALRM,sig_old);

    // imposta boom
    boom=0;
    printf("Boom=%d\n",boom);

    // imposta e blocca SIGUSR2
    sigemptyset(&block_sig);
    sigaddset(&block_sig,SIGUSR2);
    sigprocmask(SIG_BLOCK,&block_sig,&old_sig);
    // imposta e blocca inoltre SIGUSR1 cosicche' se arriva tra la
    // sospensione e la lettura della variabile sons il processo non lo
    // manchera' restando in attesa perenne. In old_sig e' bloccato solo
    // SIGUSR2
    sigemptyset(&block_sig_);
    sigaddset(&block_sig_,SIGUSR1);
    sigprocmask(SIG_BLOCK,&block_sig,&old_sig);
    // finche' boom e' uguale a zero (cioe' non e' stato ricevuto
    // SIGUSR1)
    while (!boom) {
        // sblocca il segnale SIGUSR1 dalla maschera e
        // contemporaneamente vai in attesa di segnali. Implementato
        // con un operazione atomica di modo che se arriva un segnale
        // tra la sospensione e la lettura della variabile boom, il
        // processo non lo manca e quindi non resta in attesa perenne.
        // Al ritorno sigsuspend ripristina la maschera iniziale
        // (cioe' con SIGUSR1 bloccato). Nota la ricezione di SIGUSR2 e'
        // bloccata
        sigsuspend(&old_sig);
        // guarda i segnali pendenti bloccati
        sigpending(&test_sig);
        // se era stato inviato SIGUSR2 (prima di SIGUSR1, o di un altro
        // segnale diverso da SIGUSR2, poiche' e' bloccato)
        if (sigismember(&test_sig,SIGUSR2))
            // avvisami
            printf("SIGUSR2 pending...\n");
    }
    // sblocco finale di SIGUSR1 per ripristinare la maschera iniziale
    sigprocmask(SIG_UNBLOCK,&block_sig_,NULL);

    printf("Boom=%d\nDone\n",boom);

    exit(EXIT_SUCCESS);
}
Пример #19
0
int main()
{
    dieLen = strlen(die);
    sigusr1MsgLen = strlen(sigusr1Msg);
    hupMsgLen = strlen(hupMsg);
    intMsgLen = strlen(intMsg);

    int         pid;
    sigset_t    allBlockedMask, prevMask, parentUSR1Mask,
        sighupSet, sigintSet, sigtstpSet;

    sigfillset(&sighupSet);
    sigdelset(&sighupSet, SIGHUP);
    sigfillset(&sigintSet);
    sigdelset(&sigintSet, SIGINT);
    sigfillset(&sigtstpSet);
    sigdelset(&sigtstpSet, SIGTSTP);


    sigfillset(&allBlockedMask);

    sigfillset(&parentUSR1Mask);
    sigdelset(&parentUSR1Mask, SIGUSR1);


    struct sigaction saINT, saHUP, saTSTP;
    memset(&saINT, 0, sizeof(saINT));
    memset(&saHUP, 0, sizeof(saHUP));
    memset(&saTSTP, 0, sizeof(saTSTP));
    saINT.sa_flags = 0;
    saINT.sa_handler = sigint;
    sigemptyset(&saINT.sa_mask);
    //sigaddset(&saINT.sa_mask, SIGTSTP);
    sigfillset(&saINT.sa_mask);
    saHUP.sa_flags = 0;
    saHUP.sa_handler = sighup;
    sigemptyset(&saHUP.sa_mask);
    sigfillset(&saHUP.sa_mask);
    saTSTP.sa_flags = 0;
    saTSTP.sa_handler = sigtstp;
    sigemptyset(&saTSTP.sa_mask);
    sigfillset(&saTSTP.sa_mask);

    /*   ᴧ
         |
         |
         the three of masks are filled because
         we don't want signals to interrupt their handlers (per se)
         or the other handlers

         En passant, just filling is adequate,
         there is no need to empty them priorly
    */




    struct sigaction saUSR1;
    memset(&saUSR1, 0, sizeof(saUSR1));
    saUSR1.sa_flags = 0;
    saUSR1.sa_handler = sigusr1;
    sigaction(SIGUSR1, &saUSR1, 0);

    // let the child assert signal handlers by using sigaction()
    // then let parent wake up by sending SIGUSR1 signal
    // actually it's critical section for child until unblocking (by using SIG_SETMASK &prevMask) firstly
    // and then blocking parent until waking up
    sigprocmask(SIG_BLOCK, &allBlockedMask, &prevMask);


    /* get child process */

    if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);
    }

    if (pid == 0) {   /* child */

        fprintf(stderr, "child pid %i\n", getpid());

        /* critical section to set signal handlers */
        fprintf(stderr, "child in blocking\n");

        /* set function calls */
        sigaction(SIGHUP, &saHUP, 0);
        sigaction(SIGINT, &saINT, 0);
        sigaction(SIGTSTP, &saTSTP, 0);

        /* let parent know, you can continue your process */
        kill(getppid(), SIGUSR1);

        fprintf(stderr, "child now UNblocked \n");

        /*
        sleep(1);
        printPendingSigs(stderr, "pending");
        sleep(1);
        */

        sigsuspend(&sighupSet);
        sigsuspend(&sigintSet);
        sigsuspend(&sigtstpSet);

        sigprocmask(SIG_SETMASK, &prevMask, 0);

        //     <----->

        /*
          ** If the sigsuspends were here,
                signals might be caught  <--> here
                and it gives rise to block parent forever
                until the signals come again, <--> not atomic place
        sigsuspend(&sighupSet);
        sigsuspend(&sigintSet);
        sigsuspend(&sigtstpSet);
         */

        /* here, I want to receive signals in turn */


        // Instead, I want to be here again
        fprintf(stderr, "I'm child I'm here");
        _exit(111);

    }
    else {
        /* parent */

        // usleep(500);
        fprintf(stderr, "parent pid %i\n", getpid());


        fprintf(stderr, "parent is waiting\n");
        /*
                sigsuspend, how it returnsi its work principle
                https://stackoverflow.com/a/15284248/4990642
        */
        sigsuspend(&parentUSR1Mask);
        // after returning from sigsuspend,
        // still all signals blocked here cuz of restoration of signal mask
        fprintf(stderr, "parent is running\n");

        // sleep(5);
        // try to send ctrl c ctrl z etc. signals they are already blocked


        fprintf(stderr, "\nPARENT: sending SIGHUP\n");
        kill(pid, SIGHUP);

        fprintf(stderr, "\nPARENT: sending SIGINT\n");
        kill(pid, SIGINT);

        fprintf(stderr, "\nPARENT: sending SIGTSTP\n\n");
        kill(pid, SIGTSTP);


        int status;
        wait(&status);
        if (WIFEXITED(status)){
            int returned = WEXITSTATUS(status);
            fprintf(stderr, "\nPARENT: child exited normally with status %d\n",returned);
        }
    }
    return 0;
}
Пример #20
0
int main(int argc, char **argv)
{
	struct option long_options[] = {
		// These options don't set a flag
		{"help",                      no_argument,       NULL, 'h'},
		{"alternate",                 no_argument,       NULL, 'A'},
		{"effective",                 required_argument, NULL, 'f'},
		{"duration",                  required_argument, NULL, 'd'},
		{"initial-size",              required_argument, NULL, 'i'},
		{"num-threads",               required_argument, NULL, 'n'},
		{"range",                     required_argument, NULL, 'r'},
		{"seed",                      required_argument, NULL, 's'},
		{"update-rate",               required_argument, NULL, 'u'},
		{"move-rate",                 required_argument, NULL, 'm'},
		{"snapshot-rate",             required_argument, NULL, 'a'},
		{"elasticity",                required_argument, NULL, 'x'},
		{NULL, 0, NULL, 0}
	};
	
	ht_intset_t *set;
	int i, c, size;
	val_t last = 0; 
	val_t val = 0;
	unsigned long reads, effreads, updates, effupds, moves, snapshots, aborts, 
	aborts_locked_read, aborts_locked_write, aborts_validate_read, 
	aborts_validate_write, aborts_validate_commit, aborts_invalid_memory, 
	aborts_double_write,
	max_retries, failures_because_contention;
	thread_data_t *data;
	pthread_t *threads;
	pthread_attr_t attr;
	barrier_t barrier;
	struct timeval start, end;
	struct timespec timeout;
	int duration = DEFAULT_DURATION;
	int initial = DEFAULT_INITIAL;
	int nb_threads = DEFAULT_NB_THREADS;
	long range = DEFAULT_RANGE;
	int seed = DEFAULT_SEED;
	int update = DEFAULT_UPDATE;
	int load_factor = DEFAULT_LOAD;
	int move = DEFAULT_MOVE;
	int snapshot = DEFAULT_SNAPSHOT;
	int unit_tx = DEFAULT_ELASTICITY;
	int alternate = DEFAULT_ALTERNATE;
	int effective = DEFAULT_EFFECTIVE;
	sigset_t block_set;
	
	while(1) {
		i = 0;
		c = getopt_long(argc, argv, "hAf:d:i:n:r:s:u:m:a:l:x:", long_options, &i);
		
		if(c == -1)
			break;
		
		if(c == 0 && long_options[i].flag == 0)
			c = long_options[i].val;
		
		switch(c) {
				case 0:
					// Flag is automatically set 
					break;
				case 'h':
					printf("intset -- STM stress test "
								 "(hash table)\n"
								 "\n"
								 "Usage:\n"
								 "  intset [options...]\n"
								 "\n"
								 "Options:\n"
								 "  -h, --help\n"
								 "        Print this message\n"
								 "  -A, --Alternate\n"
								 "        Consecutive insert/remove target the same value\n"
								 "  -f, --effective <int>\n"
								 "        update txs must effectively write (0=trial, 1=effective, default=" XSTR(DEFAULT_EFFECTIVE) ")\n"
								 "  -d, --duration <int>\n"
								 "        Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n"
								 "  -i, --initial-size <int>\n"
								 "        Number of elements to insert before test (default=" XSTR(DEFAULT_INITIAL) ")\n"
								 "  -n, --num-threads <int>\n"
								 "        Number of threads (default=" XSTR(DEFAULT_NB_THREADS) ")\n"
								 "  -r, --range <int>\n"
								 "        Range of integer values inserted in set (default=" XSTR(DEFAULT_RANGE) ")\n"
								 "  -s, --seed <int>\n"
								 "        RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n"
								 "  -u, --update-rate <int>\n"
								 "        Percentage of update transactions (default=" XSTR(DEFAULT_UPDATE) ")\n"
								 "  -m , --move-rate <int>\n"
								 "        Percentage of move transactions (default=" XSTR(DEFAULT_MOVE) ")\n"
								 "  -a , --snapshot-rate <int>\n"
								 "        Percentage of snapshot transactions (default=" XSTR(DEFAULT_SNAPSHOT) ")\n"
								 "  -l , --load-factor <int>\n"
								 "        Ratio of keys over buckets (default=" XSTR(DEFAULT_LOAD) ")\n"
								 "  -x, --elasticity (default=4)\n"
								 "        Use elastic transactions\n"
								 "        0 = non-protected,\n"
								 "        1 = normal transaction,\n"
								 "        2 = read elastic-tx,\n"
								 "        3 = read/add elastic-tx,\n"
								 "        4 = read/add/rem elastic-tx,\n"
								 "        5 = elastic-tx w/ optimized move.\n"
								 );
					exit(0);
				case 'A':
					alternate = 1;
					break;
				case 'f':
					effective = atoi(optarg);
					break;
				case 'd':
					duration = atoi(optarg);
					break;
				case 'i':
					initial = atoi(optarg);
					break;
				case 'n':
					nb_threads = atoi(optarg);
					break;
				case 'r':
					range = atol(optarg);
					break;
				case 's':
					seed = atoi(optarg);
					break;
				case 'u':
					update = atoi(optarg);
					break;
				case 'm':
					move = atoi(optarg);
					break;
				case 'a':
					snapshot = atoi(optarg);
					break;
				case 'l':
					load_factor = atoi(optarg);
					break;
				case 'x':
					unit_tx = atoi(optarg);
					break;
				case '?':
					printf("Use -h or --help for help\n");
					exit(0);
				default:
					exit(1);
		}
	}
	
	assert(duration >= 0);
	assert(initial >= 0);
	assert(nb_threads > 0);
	assert(range > 0 && range >= initial);
	assert(update >= 0 && update <= 100);
	assert(move >= 0 && move <= update);
	assert(snapshot >= 0 && snapshot <= (100-update));
	assert(initial < MAXHTLENGTH);
	assert(initial >= load_factor);
	
	printf("Set type     : hash table\n");
	printf("Duration     : %d\n", duration);
	printf("Initial size : %d\n", initial);
	printf("Nb threads   : %d\n", nb_threads);
	printf("Value range  : %ld\n", range);
	printf("Seed         : %d\n", seed);
	printf("Update rate  : %d\n", update);
	printf("Load factor  : %d\n", load_factor);
	printf("Move rate    : %d\n", move);
	printf("Snapshot rate: %d\n", snapshot);
	printf("Elasticity   : %d\n", unit_tx);
	printf("Alternate    : %d\n", alternate);	
	printf("Effective    : %d\n", effective);
	printf("Type sizes   : int=%d/long=%d/ptr=%d/word=%d\n",
				 (int)sizeof(int),
				 (int)sizeof(long),
				 (int)sizeof(void *),
				 (int)sizeof(uintptr_t));
	
	timeout.tv_sec = duration / 1000;
	timeout.tv_nsec = (duration % 1000) * 1000000;
	
	if ((data = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) {
		perror("malloc");
		exit(1);
	}
	if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) {
		perror("malloc");
		exit(1);
	}
	
	if (seed == 0)
		srand((int)time(0));
	else
		srand(seed);
	
	//maxhtlength = (unsigned int) initial / load_factor;
	set = ht_new();
	
	stop = 0;
	
	// Init STM 
	printf("Initializing STM\n");
	
	TM_STARTUP();
	
	// Populate set 
	printf("Adding %d entries to set\n", initial);
	i = 0;
	maxhtlength = (int) (initial / load_factor);
	while (i < initial) {
		val = rand_range(range);
		if (ht_add(set, val, 0)) {
		  last = val;
		  i++;			
		}
	}
	size = ht_size(set);
	printf("Set size     : %d\n", size);
	printf("Bucket amount: %d\n", maxhtlength);
	printf("Load         : %d\n", load_factor);
	
	// Access set from all threads 
	barrier_init(&barrier, nb_threads + 1);
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
	for (i = 0; i < nb_threads; i++) {
		printf("Creating thread %d\n", i);
		data[i].first = last;
		data[i].range = range;
		data[i].update = update;
		data[i].load_factor = load_factor;
		data[i].move = move;
		data[i].snapshot = snapshot;
		data[i].unit_tx = unit_tx;
		data[i].alternate = alternate;
		data[i].effective = effective;
		data[i].nb_add = 0;
		data[i].nb_added = 0;
		data[i].nb_remove = 0;
		data[i].nb_removed = 0;
		data[i].nb_move = 0;
		data[i].nb_moved = 0;
		data[i].nb_snapshot = 0;
		data[i].nb_snapshoted = 0;
		data[i].nb_contains = 0;
		data[i].nb_found = 0;
		data[i].nb_aborts = 0;
		data[i].nb_aborts_locked_read = 0;
		data[i].nb_aborts_locked_write = 0;
		data[i].nb_aborts_validate_read = 0;
		data[i].nb_aborts_validate_write = 0;
		data[i].nb_aborts_validate_commit = 0;
		data[i].nb_aborts_invalid_memory = 0;
		data[i].nb_aborts_double_write = 0;
		data[i].max_retries = 0;
		data[i].seed = rand();
		data[i].set = set;
		data[i].barrier = &barrier;
		data[i].failures_because_contention = 0;
		if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) {
			fprintf(stderr, "Error creating thread\n");
			exit(1);
		}
	}
	pthread_attr_destroy(&attr);
	
	// Start threads 
	barrier_cross(&barrier);
	
	printf("STARTING...\n");
	gettimeofday(&start, NULL);
	if (duration > 0) {
		nanosleep(&timeout, NULL);
	} else {
		sigemptyset(&block_set);
		sigsuspend(&block_set);
	}
	AO_store_full(&stop, 1);
	gettimeofday(&end, NULL);
	printf("STOPPING...\n");
	
	// Wait for thread completion 
	for (i = 0; i < nb_threads; i++) {
		if (pthread_join(threads[i], NULL) != 0) {
			fprintf(stderr, "Error waiting for thread completion\n");
			exit(1);
		}
	}
	duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000);
	aborts = 0;
	aborts_locked_read = 0;
	aborts_locked_write = 0;
	aborts_validate_read = 0;
	aborts_validate_write = 0;
	aborts_validate_commit = 0;
	aborts_invalid_memory = 0;
	aborts_double_write = 0;
	failures_because_contention = 0;
	reads = 0;
	effreads = 0;
	updates = 0;
	effupds = 0;
	moves = 0;
	snapshots = 0;
	max_retries = 0;
	for (i = 0; i < nb_threads; i++) {
		printf("Thread %d\n", i);
		printf("  #add        : %lu\n", data[i].nb_add);
		printf("    #added    : %lu\n", data[i].nb_added);
		printf("  #remove     : %lu\n", data[i].nb_remove);
		printf("    #removed  : %lu\n", data[i].nb_removed);
		printf("  #contains   : %lu\n", data[i].nb_contains);
		printf("  #found      : %lu\n", data[i].nb_found);
		printf("  #move       : %lu\n", data[i].nb_move);
		printf("  #moved      : %lu\n", data[i].nb_moved);
		printf("  #snapshot   : %lu\n", data[i].nb_snapshot);
		printf("  #snapshoted : %lu\n", data[i].nb_snapshoted);
		printf("  #aborts     : %lu\n", data[i].nb_aborts);
		printf("    #lock-r   : %lu\n", data[i].nb_aborts_locked_read);
		printf("    #lock-w   : %lu\n", data[i].nb_aborts_locked_write);
		printf("    #val-r    : %lu\n", data[i].nb_aborts_validate_read);
		printf("    #val-w    : %lu\n", data[i].nb_aborts_validate_write);
		printf("    #val-c    : %lu\n", data[i].nb_aborts_validate_commit);
		printf("    #inv-mem  : %lu\n", data[i].nb_aborts_invalid_memory);
		printf("    #dup-w  : %lu\n", data[i].nb_aborts_double_write);
		printf("    #failures : %lu\n", data[i].failures_because_contention);
		printf("  Max retries : %lu\n", data[i].max_retries);
		aborts += data[i].nb_aborts;
		aborts_locked_read += data[i].nb_aborts_locked_read;
		aborts_locked_write += data[i].nb_aborts_locked_write;
		aborts_validate_read += data[i].nb_aborts_validate_read;
		aborts_validate_write += data[i].nb_aborts_validate_write;
		aborts_validate_commit += data[i].nb_aborts_validate_commit;
		aborts_invalid_memory += data[i].nb_aborts_invalid_memory;
		aborts_double_write += data[i].nb_aborts_double_write;
		failures_because_contention += data[i].failures_because_contention;
		reads += (data[i].nb_contains + data[i].nb_snapshot);
		effreads += data[i].nb_contains + 
		(data[i].nb_add - data[i].nb_added) + 
		(data[i].nb_remove - data[i].nb_removed) + 
		(data[i].nb_move - data[i].nb_moved) +
		data[i].nb_snapshoted;
		updates += (data[i].nb_add + data[i].nb_remove + data[i].nb_move);
		effupds += data[i].nb_removed + data[i].nb_added + data[i].nb_moved; 
		moves += data[i].nb_move;
		snapshots += data[i].nb_snapshot;
		size += data[i].nb_added - data[i].nb_removed;
		if (max_retries < data[i].max_retries)
			max_retries = data[i].max_retries;
	}
	printf("Set size      : %d (expected: %d)\n", ht_size(set), size);
	printf("Duration      : %d (ms)\n", duration);
	printf("#txs          : %lu (%f / s)\n", reads + updates + moves + snapshots, (reads + updates + moves + snapshots) * 1000.0 / duration);
	
	printf("#read txs     : ");
	if (effective) {
		printf("%lu (%f / s)\n", effreads, effreads * 1000.0 / duration);
		printf("  #cont/snpsht: %lu (%f / s)\n", reads, reads * 1000.0 / duration);
	} else printf("%lu (%f / s)\n", reads, reads * 1000.0 / duration);
	
	printf("#eff. upd rate: %f \n", 100.0 * effupds / (effupds + effreads));
	
	printf("#update txs   : ");
	if (effective) {
		printf("%lu (%f / s)\n", effupds, effupds * 1000.0 / duration);
		printf("  #upd trials : %lu (%f / s)\n", updates, updates * 1000.0 / 
					 duration);
	} else printf("%lu (%f / s)\n", updates, updates * 1000.0 / duration);
	
	printf("#move txs     : %lu (%f / s)\n", moves, moves * 1000.0 / duration);
	printf("#snapshot txs : %lu (%f / s)\n", snapshots, snapshots * 1000.0 / duration);
	printf("#aborts       : %lu (%f / s)\n", aborts, aborts * 1000.0 / duration);
	printf("  #lock-r     : %lu (%f / s)\n", aborts_locked_read, aborts_locked_read * 1000.0 / duration);
	printf("  #lock-w     : %lu (%f / s)\n", aborts_locked_write, aborts_locked_write * 1000.0 / duration);
	printf("  #val-r      : %lu (%f / s)\n", aborts_validate_read, aborts_validate_read * 1000.0 / duration);
	printf("  #val-w      : %lu (%f / s)\n", aborts_validate_write, aborts_validate_write * 1000.0 / duration);
	printf("  #val-c      : %lu (%f / s)\n", aborts_validate_commit, aborts_validate_commit * 1000.0 / duration);
	printf("  #inv-mem    : %lu (%f / s)\n", aborts_invalid_memory, aborts_invalid_memory * 1000.0 / duration);
	printf("  #dup-w      : %lu (%f / s)\n", aborts_double_write, aborts_double_write * 1000.0 / duration);
	printf("  #failures   : %lu\n",  failures_because_contention);
	printf("Max retries   : %lu\n", max_retries);
	
	// Delete set 
	ht_delete(set);
	
	// Cleanup STM 
	TM_SHUTDOWN();
	
	free(threads);
	free(data);
	
	return 0;
}
Пример #21
0
int main(int argc, char *argv[])
{
	mqd_t mqd;
	void *buff;
	ssize_t n;
	sigset_t zeromask, newmask, oldmask;
	struct mq_attr attr;
	struct sigevent sigev;

	if (2 != argc){
		printf("Usage: mqnotifysig2 <name>\n");
		exit(1);
	}

	if (-1 == (mqd = mq_open(argv[1], O_RDONLY))){
		printf("mq_open %s failed\n", argv[1]);
		exit(1);
	}

	if (mq_getattr(mqd, &attr)){
		printf("get attr failed\n");
		exit(1);
	}
	
	if (!(buff = malloc(attr.mq_msgsize))){
		printf("Alloc buff failed\n");
		exit(1);
	}

	sigemptyset(&zeromask);
	sigemptyset(&newmask);
	sigemptyset(&oldmask);
	sigaddset(&newmask, SIGUSR1);

	signal(SIGUSR1, sig_usr1);
	sigev.sigev_notify = SIGEV_SIGNAL;
	sigev.sigev_signo = SIGUSR1;
	if (-1 == mq_notify(mqd, &sigev)){
		printf("Set mq_notify failed\n");
		exit(1);
	}

	for (;;){
		sigprocmask(SIG_BLOCK, &newmask, &oldmask);
		while(mqflag == 0){
			sigsuspend(&zeromask);
		}
		mqflag = 0;

		if (-1 == mq_notify(mqd, &sigev)){
			printf("Set mq_notify failed\n");
			exit(1);
		}

		n = mq_receive(mqd, buff, attr.mq_msgsize, NULL);
		if (n == -1){
			printf("mq_receive failed\n");
			exit(1);
		}

		printf("read %ld bytes\n", (long)n);
		sigprocmask(SIG_UNBLOCK, &newmask, NULL);
	}
	exit(0);
}
Пример #22
0
void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
    char              *title;
    u_char            *p;
    size_t             size;
    ngx_int_t          i;
    ngx_uint_t         n, sigio;
    sigset_t           set;
    struct itimerval   itv;
    ngx_uint_t         live;
    ngx_msec_t         delay;
    ngx_listening_t   *ls;
    ngx_core_conf_t   *ccf;

    //屏蔽一系列信号,防止被打扰
    sigemptyset(&set);
    sigaddset(&set, SIGCHLD);
    sigaddset(&set, SIGALRM);
    sigaddset(&set, SIGIO);
    sigaddset(&set, SIGINT);
    sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));

    if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed");
    }

    sigemptyset(&set);


    size = sizeof(master_process);

    for (i = 0; i < ngx_argc; i++) {
        size += ngx_strlen(ngx_argv[i]) + 1;
    }

    title = ngx_pnalloc(cycle->pool, size);

    p = ngx_cpymem(title, master_process, sizeof(master_process) - 1);
    for (i = 0; i < ngx_argc; i++) {
        *p++ = ' ';
        p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size);
    }

    ngx_setproctitle(title);

    //master进程获取core模块配置,ccf中有要创建多少个worker的设定
    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);

    //启动worker,这时已经有了worker进程
    ngx_start_worker_processes(cycle, ccf->worker_processes,            
                               NGX_PROCESS_RESPAWN);
    ngx_start_cache_manager_processes(cycle, 0);  //创建有关cache的子进程

    ngx_new_binary = 0;
    delay = 0;
    sigio = 0;
    live = 1;

    for ( ;; ) {
        //delay用来等待子进程退出的时间,由于我们接受到SIGINT信号后,我们需要先发送信号给子进程,
        //而子进程的退出需要一定的时间,超时时如果子进程已退出,我们父进程就直接退出,
        //否则发送sigkill信号给子进程(强制退出),然后再退出。  
        if (delay) {
            if (ngx_sigalrm) {
                sigio = 0;
                delay *= 2;
                ngx_sigalrm = 0;
            }

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "termination cycle: %d", delay);

            itv.it_interval.tv_sec = 0;
            itv.it_interval.tv_usec = 0;
            itv.it_value.tv_sec = delay / 1000;
            itv.it_value.tv_usec = (delay % 1000 ) * 1000;

            //设置定时器
            if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "setitimer() failed");
            }
        }

        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend");

        //延时,等待信号
        sigsuspend(&set);  //调用这个将master进程挂起来

        ngx_time_update();

        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "wake up, sigio %i", sigio);
        
        //ngx_reap为1,说明有子进程已经退出
        if (ngx_reap) {
            ngx_reap = 0;
            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");

            //这个里面处理退出的子进程(有的worker异常退出,这时我们就需要重启这个worker ),如果所有子进程都退出则会返回0.  
            live = ngx_reap_children(cycle);
        }

        //如果没有存活的子进程,并且收到了ngx_terminate或者ngx_quit信号,则master退出。 
        if (!live && (ngx_terminate || ngx_quit)) {
            ngx_master_process_exit(cycle);
        }
    
        //收到了sigint信号
        if (ngx_terminate) {
            //设置延时
            if (delay == 0) {
                delay = 50;
            }

            if (sigio) {
                sigio--;
                continue;
            }

            sigio = ccf->worker_processes + 2 /* cache processes */;

            if (delay > 1000) {
                //如果超时,则强制杀死worker 
                ngx_signal_worker_processes(cycle, SIGKILL);
            } else {
                //负责发送sigint给worker,让它退出
                ngx_signal_worker_processes(cycle,
                                       ngx_signal_value(NGX_TERMINATE_SIGNAL));
            }

            continue;
        }

        //收到quit信号
        if (ngx_quit) {
            //发送给worker quit信号
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));

            ls = cycle->listening.elts;
            for (n = 0; n < cycle->listening.nelts; n++) {
                if (ngx_close_socket(ls[n].fd) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                                  ngx_close_socket_n " %V failed",
                                  &ls[n].addr_text);
                }
            }
            cycle->listening.nelts = 0;

            continue;
        }

        //收到需要reconfig的信号 
        if (ngx_reconfigure) {
            ngx_reconfigure = 0;

            //判断是否热代码替换后的新的代码还在运行中(也就是还没退出当前的master)。如果还在运行中,则不需要重新初始化config
            if (ngx_new_binary) {
                ngx_start_worker_processes(cycle, ccf->worker_processes,
                                           NGX_PROCESS_RESPAWN);
                ngx_start_cache_manager_processes(cycle, 0);
                ngx_noaccepting = 0;

                continue;
            }

            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");
            
            //重新初始化config,并重新启动新的worker
            cycle = ngx_init_cycle(cycle);
            if (cycle == NULL) {
                cycle = (ngx_cycle_t *) ngx_cycle;
                continue;
            }

            ngx_cycle = cycle;
            ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
                                                   ngx_core_module);
            ngx_start_worker_processes(cycle, ccf->worker_processes,
                                       NGX_PROCESS_JUST_RESPAWN);
            ngx_start_cache_manager_processes(cycle, 1);
            live = 1;
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
        }

        if (ngx_restart) {
            ngx_restart = 0;
            ngx_start_worker_processes(cycle, ccf->worker_processes,
                                       NGX_PROCESS_RESPAWN);
            ngx_start_cache_manager_processes(cycle, 0);
            live = 1;
        }

        //重新打开
        if (ngx_reopen) {
            ngx_reopen = 0;
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
            ngx_reopen_files(cycle, ccf->user);
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_REOPEN_SIGNAL));
        }

        //热代码替换
        if (ngx_change_binary) {
            ngx_change_binary = 0;
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary");
            //进行热代码替换,这里是调用execve来执行新的代码
            ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv);
        }

        //接受到停止accept连接,其实也就是worker退出(有区别的是,这里master不需要退出)
        if (ngx_noaccept) {
            ngx_noaccept = 0;
            ngx_noaccepting = 1;
            //给worker发送信号
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
        }
    }
}
Пример #23
0
void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
    char              *title;
    u_char            *p;
    size_t             size;
    ngx_int_t          i;
    ngx_uint_t         n, sigio;
    sigset_t           set;
    struct itimerval   itv;
    ngx_uint_t         live;
    ngx_msec_t         delay;
    ngx_listening_t   *ls;
    ngx_core_conf_t   *ccf;

    sigemptyset(&set);
    sigaddset(&set, SIGCHLD);
    sigaddset(&set, SIGALRM);
    sigaddset(&set, SIGIO);
    sigaddset(&set, SIGINT);
    sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));

    if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed");
    }

    sigemptyset(&set);


    size = sizeof(master_process);

    for (i = 0; i < ngx_argc; i++) {
        size += ngx_strlen(ngx_argv[i]) + 1;
    }

    title = ngx_pnalloc(cycle->pool, size);

    p = ngx_cpymem(title, master_process, sizeof(master_process) - 1);
    for (i = 0; i < ngx_argc; i++) {
        *p++ = ' ';
        p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size);
    }

    ngx_setproctitle(title);


    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);

    ngx_start_worker_processes(cycle, ccf->worker_processes,
                               NGX_PROCESS_RESPAWN);
    ngx_start_cache_manager_processes(cycle, 0);

    ngx_new_binary = 0;
    delay = 0;
    sigio = 0;
    live = 1;

    for ( ;; ) {
        if (delay) {
            if (ngx_sigalrm) {
                sigio = 0;
                delay *= 2;
                ngx_sigalrm = 0;
            }

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "termination cycle: %d", delay);

            itv.it_interval.tv_sec = 0;
            itv.it_interval.tv_usec = 0;
            itv.it_value.tv_sec = delay / 1000;
            itv.it_value.tv_usec = (delay % 1000 ) * 1000;

            if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "setitimer() failed");
            }
        }

        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend");

        sigsuspend(&set);

        ngx_time_update();

        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "wake up, sigio %i", sigio);

        if (ngx_reap) {
            ngx_reap = 0;
            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");

            live = ngx_reap_children(cycle);
        }

        if (!live && (ngx_terminate || ngx_quit)) {
            ngx_master_process_exit(cycle);
        }

        if (ngx_terminate) {
            if (delay == 0) {
                delay = 50;
            }

            if (sigio) {
                sigio--;
                continue;
            }

            sigio = ccf->worker_processes + 2 /* cache processes */;

            if (delay > 1000) {
                ngx_signal_worker_processes(cycle, SIGKILL);
            } else {
                ngx_signal_worker_processes(cycle,
                                       ngx_signal_value(NGX_TERMINATE_SIGNAL));
            }

            continue;
        }

        if (ngx_quit) {
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));

            ls = cycle->listening.elts;
            for (n = 0; n < cycle->listening.nelts; n++) {
                if (ngx_close_socket(ls[n].fd) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                                  ngx_close_socket_n " %V failed",
                                  &ls[n].addr_text);
                }
            }
            cycle->listening.nelts = 0;

            continue;
        }

        if (ngx_reconfigure) {
            ngx_reconfigure = 0;

            if (ngx_new_binary) {
                ngx_start_worker_processes(cycle, ccf->worker_processes,
                                           NGX_PROCESS_RESPAWN);
                ngx_start_cache_manager_processes(cycle, 0);
                ngx_noaccepting = 0;

                continue;
            }

            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");

            cycle = ngx_init_cycle(cycle);
            if (cycle == NULL) {
                cycle = (ngx_cycle_t *) ngx_cycle;
                continue;
            }

            ngx_cycle = cycle;
            ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
                                                   ngx_core_module);
            ngx_start_worker_processes(cycle, ccf->worker_processes,
                                       NGX_PROCESS_JUST_RESPAWN);
            ngx_start_cache_manager_processes(cycle, 1);
            live = 1;
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
        }

        if (ngx_restart) {
            ngx_restart = 0;
            ngx_start_worker_processes(cycle, ccf->worker_processes,
                                       NGX_PROCESS_RESPAWN);
            ngx_start_cache_manager_processes(cycle, 0);
            live = 1;
        }

        if (ngx_reopen) {
            ngx_reopen = 0;
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
            ngx_reopen_files(cycle, ccf->user);
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_REOPEN_SIGNAL));
        }

        if (ngx_change_binary) {
            ngx_change_binary = 0;
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary");
            ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv);
        }

        if (ngx_noaccept) {
            ngx_noaccept = 0;
            ngx_noaccepting = 1;
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
        }
    }
}
Пример #24
0
// Signal handler for suspended thread
static void sigsuspend_handler(int sig)
{
	sem_post(&suspend_ack_sem);
	sigsuspend(&suspend_handler_mask);
}
Пример #25
0
/*
 * Use SMF error codes only on return or exit.
 */
int
main(int argc, char *argv[])
{
	struct sigaction	act;
	sigset_t		set;
	uid_t			uid;
	int			pfd = -1;
	uint_t			sigval;
	struct rlimit		rl;
	int			orig_limit;

	smbd.s_pname = basename(argv[0]);
	openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);

	if (smbd_setup_options(argc, argv) != 0)
		return (SMF_EXIT_ERR_FATAL);

	if ((uid = getuid()) != smbd.s_uid) {
		smbd_report("user %d: %s", uid, strerror(EPERM));
		return (SMF_EXIT_ERR_FATAL);
	}

	if (getzoneid() != GLOBAL_ZONEID) {
		smbd_report("non-global zones are not supported");
		return (SMF_EXIT_ERR_FATAL);
	}

	if (is_system_labeled()) {
		smbd_report("Trusted Extensions not supported");
		return (SMF_EXIT_ERR_FATAL);
	}

	if (smbd_already_running())
		return (SMF_EXIT_OK);

	/*
	 * Raise the file descriptor limit to accommodate simultaneous user
	 * authentications/file access.
	 */
	if ((getrlimit(RLIMIT_NOFILE, &rl) == 0) &&
	    (rl.rlim_cur < rl.rlim_max)) {
		orig_limit = rl.rlim_cur;
		rl.rlim_cur = rl.rlim_max;
		if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
			smbd_report("Failed to raise file descriptor limit"
			    " from %d to %d", orig_limit, rl.rlim_cur);
	}

	(void) sigfillset(&set);
	(void) sigdelset(&set, SIGABRT);

	(void) sigfillset(&act.sa_mask);
	act.sa_handler = smbd_sig_handler;
	act.sa_flags = 0;

	(void) sigaction(SIGABRT, &act, NULL);
	(void) sigaction(SIGTERM, &act, NULL);
	(void) sigaction(SIGHUP, &act, NULL);
	(void) sigaction(SIGINT, &act, NULL);
	(void) sigaction(SIGPIPE, &act, NULL);
	(void) sigaction(SIGUSR1, &act, NULL);

	(void) sigdelset(&set, SIGTERM);
	(void) sigdelset(&set, SIGHUP);
	(void) sigdelset(&set, SIGINT);
	(void) sigdelset(&set, SIGPIPE);
	(void) sigdelset(&set, SIGUSR1);

	if (smbd.s_fg) {
		(void) sigdelset(&set, SIGTSTP);
		(void) sigdelset(&set, SIGTTIN);
		(void) sigdelset(&set, SIGTTOU);

		if (smbd_service_init() != 0) {
			smbd_report("service initialization failed");
			exit(SMF_EXIT_ERR_FATAL);
		}
	} else {
		/*
		 * "pfd" is a pipe descriptor -- any fatal errors
		 * during subsequent initialization of the child
		 * process should be written to this pipe and the
		 * parent will report this error as the exit status.
		 */
		pfd = smbd_daemonize_init();

		if (smbd_service_init() != 0) {
			smbd_report("daemon initialization failed");
			exit(SMF_EXIT_ERR_FATAL);
		}

		smbd_daemonize_fini(pfd, SMF_EXIT_OK);
	}

	(void) atexit(smb_kmod_stop);

	while (!smbd.s_shutting_down) {
		if (smbd.s_sigval == 0 && smbd.s_refreshes == 0)
			(void) sigsuspend(&set);

		sigval = atomic_swap_uint(&smbd.s_sigval, 0);

		switch (sigval) {
		case 0:
		case SIGPIPE:
		case SIGABRT:
			break;

		case SIGHUP:
			syslog(LOG_DEBUG, "refresh requested");
			(void) pthread_cond_signal(&refresh_cond);
			break;

		case SIGUSR1:
			smb_log_dumpall();
			break;

		default:
			/*
			 * Typically SIGINT or SIGTERM.
			 */
			smbd.s_shutting_down = B_TRUE;
			break;
		}
	}

	smbd_service_fini();
	closelog();
	return ((smbd.s_fatal_error) ? SMF_EXIT_ERR_FATAL : SMF_EXIT_OK);
}
asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
{
	sigset_t blocked;
	siginitset(&blocked, mask);
	return sigsuspend(&blocked);
}
Пример #27
0
int
main(int argc, char *argv[])
{
	int i, j;
	int error, fnd_dup, len, mustfreeai = 0, start_uidpos;
	struct nfsd_idargs nid;
	struct passwd *pwd;
	struct group *grp;
	int sock, one = 1;
	SVCXPRT *udptransp;
	u_short portnum;
	sigset_t signew;
	char hostname[MAXHOSTNAMELEN + 1], *cp;
	struct addrinfo *aip, hints;
	static uid_t check_dups[MAXUSERMAX];

	if (modfind("nfscommon") < 0) {
		/* Not present in kernel, try loading it */
		if (kldload("nfscommon") < 0 ||
		    modfind("nfscommon") < 0)
			errx(1, "Experimental nfs subsystem is not available");
	}

	/*
	 * First, figure out what our domain name and Kerberos Realm
	 * seem to be. Command line args may override these later.
	 */
	if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
		if ((cp = strchr(hostname, '.')) != NULL &&
		    *(cp + 1) != '\0') {
			dnsname = cp + 1;
		} else {
			memset((void *)&hints, 0, sizeof (hints));
			hints.ai_flags = AI_CANONNAME;
			error = getaddrinfo(hostname, NULL, &hints, &aip);
			if (error == 0) {
			    if (aip->ai_canonname != NULL &&
				(cp = strchr(aip->ai_canonname, '.')) != NULL
				&& *(cp + 1) != '\0') {
					dnsname = cp + 1;
					mustfreeai = 1;
				} else {
					freeaddrinfo(aip);
				}
			}
		}
	}
	nid.nid_usermax = DEFUSERMAX;
	nid.nid_usertimeout = defusertimeout;

	argc--;
	argv++;
	while (argc >= 1) {
		if (!strcmp(*argv, "-domain")) {
			if (argc == 1)
				usage();
			argc--;
			argv++;
			strncpy(hostname, *argv, MAXHOSTNAMELEN);
			hostname[MAXHOSTNAMELEN] = '\0';
			dnsname = hostname;
		} else if (!strcmp(*argv, "-verbose")) {
			verbose = 1;
		} else if (!strcmp(*argv, "-force")) {
			forcestart = 1;
		} else if (!strcmp(*argv, "-usermax")) {
			if (argc == 1)
				usage();
			argc--;
			argv++;
			i = atoi(*argv);
			if (i < MINUSERMAX || i > MAXUSERMAX) {
				fprintf(stderr,
				    "usermax %d out of range %d<->%d\n", i,
				    MINUSERMAX, MAXUSERMAX);
				usage();
			}
			nid.nid_usermax = i;
		} else if (!strcmp(*argv, "-usertimeout")) {
			if (argc == 1)
				usage();
			argc--;
			argv++;
			i = atoi(*argv);
			if (i < 0 || i > 100000) {
				fprintf(stderr,
				    "usertimeout %d out of range 0<->100000\n",
				    i);
				usage();
			}
			nid.nid_usertimeout = defusertimeout = i * 60;
		} else if (nfsuserdcnt == -1) {
			nfsuserdcnt = atoi(*argv);
			if (nfsuserdcnt < 1)
				usage();
			if (nfsuserdcnt > MAXNFSUSERD) {
				warnx("nfsuserd count %d; reset to %d",
				    nfsuserdcnt, DEFNFSUSERD);
				nfsuserdcnt = DEFNFSUSERD;
			}
		} else {
			usage();
		}
		argc--;
		argv++;
	}
	if (nfsuserdcnt < 1)
		nfsuserdcnt = DEFNFSUSERD;

	/*
	 * Strip off leading and trailing '.'s in domain name and map
	 * alphabetics to lower case.
	 */
	while (*dnsname == '.')
		dnsname++;
	if (*dnsname == '\0')
		errx(1, "Domain name all '.'");
	len = strlen(dnsname);
	cp = dnsname + len - 1;
	while (*cp == '.') {
		*cp = '\0';
		len--;
		cp--;
	}
	for (i = 0; i < len; i++) {
		if (!isascii(dnsname[i]))
			errx(1, "Domain name has non-ascii char");
		if (isupper(dnsname[i]))
			dnsname[i] = tolower(dnsname[i]);
	}

	/*
	 * If the nfsuserd died off ungracefully, this is necessary to
	 * get them to start again.
	 */
	if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
		errx(1, "Can't do nfssvc() to delete the port");

	if (verbose)
		fprintf(stderr,
		    "nfsuserd: domain=%s usermax=%d usertimeout=%d\n",
		    dnsname, nid.nid_usermax, nid.nid_usertimeout);

	for (i = 0; i < nfsuserdcnt; i++)
		slaves[i] = (pid_t)-1;

	/*
	 * Set up the service port to accept requests via UDP from
	 * localhost (127.0.0.1).
	 */
	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
		err(1, "cannot create udp socket");

	/*
	 * Not sure what this does, so I'll leave it here for now.
	 */
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
	
	if ((udptransp = svcudp_create(sock)) == NULL)
		err(1, "Can't set up socket");

	/*
	 * By not specifying a protocol, it is linked into the
	 * dispatch queue, but not registered with portmapper,
	 * which is just what I want.
	 */
	if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
	    nfsuserdsrv, 0))
		err(1, "Can't register nfsuserd");

	/*
	 * Tell the kernel what my port# is.
	 */
	portnum = htons(udptransp->xp_port);
#ifdef DEBUG
	printf("portnum=0x%x\n", portnum);
#else
	if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) {
		if (errno == EPERM) {
			fprintf(stderr,
			    "Can't start nfsuserd when already running");
			fprintf(stderr,
			    " If not running, use the -force option.\n");
		} else {
			fprintf(stderr, "Can't do nfssvc() to add port\n");
		}
		exit(1);
	}
#endif

	pwd = getpwnam(defaultuser);
	if (pwd)
		nid.nid_uid = pwd->pw_uid;
	else
		nid.nid_uid = defaultuid;
	grp = getgrnam(defaultgroup);
	if (grp)
		nid.nid_gid = grp->gr_gid;
	else
		nid.nid_gid = defaultgid;
	nid.nid_name = dnsname;
	nid.nid_namelen = strlen(nid.nid_name);
	nid.nid_flag = NFSID_INITIALIZE;
#ifdef DEBUG
	printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid, 
	    nid.nid_name);
#else
	error = nfssvc(NFSSVC_IDNAME, &nid);
	if (error)
		errx(1, "Can't initialize nfs user/groups");
#endif

	i = 0;
	/*
	 * Loop around adding all groups.
	 */
	setgrent();
	while (i < nid.nid_usermax && (grp = getgrent())) {
		nid.nid_gid = grp->gr_gid;
		nid.nid_name = grp->gr_name;
		nid.nid_namelen = strlen(grp->gr_name);
		nid.nid_flag = NFSID_ADDGID;
#ifdef DEBUG
		printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
#else
		error = nfssvc(NFSSVC_IDNAME, &nid);
		if (error)
			errx(1, "Can't add group %s", grp->gr_name);
#endif
		i++;
	}

	/*
	 * Loop around adding all users.
	 */
	start_uidpos = i;
	setpwent();
	while (i < nid.nid_usermax && (pwd = getpwent())) {
		fnd_dup = 0;
		/*
		 * Yes, this is inefficient, but it is only done once when
		 * the daemon is started and will run in a fraction of a second
		 * for nid_usermax at 10000. If nid_usermax is cranked up to
		 * 100000, it will take several seconds, depending on the CPU.
		 */
		for (j = 0; j < (i - start_uidpos); j++)
			if (check_dups[j] == pwd->pw_uid) {
				/* Found another entry for uid, so skip it */
				fnd_dup = 1;
				break;
			}
		if (fnd_dup != 0)
			continue;
		check_dups[i - start_uidpos] = pwd->pw_uid;
		nid.nid_uid = pwd->pw_uid;
		nid.nid_name = pwd->pw_name;
		nid.nid_namelen = strlen(pwd->pw_name);
		nid.nid_flag = NFSID_ADDUID;
#ifdef DEBUG
		printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
#else
		error = nfssvc(NFSSVC_IDNAME, &nid);
		if (error)
			errx(1, "Can't add user %s", pwd->pw_name);
#endif
		i++;
	}

	/*
	 * I should feel guilty for not calling this for all the above exit()
	 * upon error cases, but I don't.
	 */
	if (mustfreeai)
		freeaddrinfo(aip);

#ifdef DEBUG
	exit(0);
#endif
	/*
	 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
	 * end up bogus.
	 */
	sigemptyset(&signew);
	sigaddset(&signew, SIGUSR1);
	sigaddset(&signew, SIGCHLD);
	sigprocmask(SIG_BLOCK, &signew, NULL);

	daemon(0, 0);
	(void)signal(SIGHUP, SIG_IGN);
	(void)signal(SIGINT, SIG_IGN);
	(void)signal(SIGQUIT, SIG_IGN);
	(void)signal(SIGTERM, SIG_IGN);
	(void)signal(SIGUSR1, cleanup_term);
	(void)signal(SIGCHLD, cleanup_term);

	openlog("nfsuserd:", LOG_PID, LOG_DAEMON);

	/*
	 * Fork off the slave daemons that do the work. All the master
	 * does is kill them off and cleanup.
	 */
	for (i = 0; i < nfsuserdcnt; i++) {
		slaves[i] = fork();
		if (slaves[i] == 0) {
			im_a_slave = 1;
			setproctitle("slave");
			sigemptyset(&signew);
			sigaddset(&signew, SIGUSR1);
			sigprocmask(SIG_UNBLOCK, &signew, NULL);

			/*
			 * and away we go.
			 */
			svc_run();
			syslog(LOG_ERR, "nfsuserd died: %m");
			exit(1);
		} else if (slaves[i] < 0) {
			syslog(LOG_ERR, "fork: %m");
		}
	}

	/*
	 * Just wait for SIGUSR1 or a child to die and then...
	 * As the Governor of California would say, "Terminate them".
	 */
	setproctitle("master");
	sigemptyset(&signew);
	while (1)
		sigsuspend(&signew);
}
static void
suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
{
#if defined(__native_client__)
	g_assert_not_reached ();
#else
	int old_errno = errno;
	int hp_save_index = mono_hazard_pointer_save_for_signal_handler ();


	MonoThreadInfo *current = mono_thread_info_current ();
	gboolean ret;

	THREADS_SUSPEND_DEBUG ("SIGNAL HANDLER FOR %p [%p]\n", current, (void*)current->native_handle);
	if (current->syscall_break_signal) {
		current->syscall_break_signal = FALSE;
		THREADS_SUSPEND_DEBUG ("\tsyscall break for %p\n", current);
		mono_threads_notify_initiator_of_abort (current);
		goto done;
	}

	/* Have we raced with self suspend? */
	if (!mono_threads_transition_finish_async_suspend (current)) {
		current->suspend_can_continue = TRUE;
		THREADS_SUSPEND_DEBUG ("\tlost race with self suspend %p\n", current);
		goto done;
	}

	ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&current->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], context);

	/* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
	current->suspend_can_continue = ret;

	/*
	Block the restart signal.
	We need to block the restart signal while posting to the suspend_ack semaphore or we race to sigsuspend,
	which might miss the signal and get stuck.
	*/
	pthread_sigmask (SIG_BLOCK, &suspend_ack_signal_mask, NULL);

	/* This thread is doomed, all we can do is give up and let the suspender recover. */
	if (!ret) {
		THREADS_SUSPEND_DEBUG ("\tThread is dying, failed to capture state %p\n", current);
		mono_threads_transition_async_suspend_compensation (current);

		/* We're done suspending */
		mono_threads_notify_initiator_of_suspend (current);

		/* Unblock the restart signal. */
		pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL);

		goto done;
	}

	/* We're done suspending */
	mono_threads_notify_initiator_of_suspend (current);

	do {
		current->signal = 0;
		sigsuspend (&suspend_signal_mask);
	} while (current->signal != restart_signal_num);

	/* Unblock the restart signal. */
	pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL);

	if (current->async_target) {
#if MONO_ARCH_HAS_MONO_CONTEXT
		MonoContext tmp = current->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx;
		mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
		current->async_target = current->user_data = NULL;
		mono_monoctx_to_sigctx (&tmp, context);
#else
		g_error ("The new interruption machinery requires a working mono-context");
#endif
	}

	/* We're done resuming */
	mono_threads_notify_initiator_of_resume (current);

done:
	mono_hazard_pointer_restore_for_signal_handler (hp_save_index);
	errno = old_errno;
#endif
}
Пример #29
0
int main(int argc, char **argv)
{
  set_cpu(the_cores[0]);
  ssalloc_init();
  seeds = seed_rand();

#ifdef PAPI
  if (PAPI_VER_CURRENT != PAPI_library_init(PAPI_VER_CURRENT))
  {
    printf("PAPI_library_init error.\n");
    return 0; 
  }
  else 
  {
    printf("PAPI_library_init success.\n");
  }

  if (PAPI_OK != PAPI_query_event(PAPI_L1_DCM))
  {
    printf("Cannot count PAPI_L1_DCM.");
  }
  printf("PAPI_query_event: PAPI_L1_DCM OK.\n");
  if (PAPI_OK != PAPI_query_event(PAPI_L2_DCM))
  {
    printf("Cannot count PAPI_L2_DCM.");
  }
  printf("PAPI_query_event: PAPI_L2_DCM OK.\n");

#endif

  struct option long_options[] = {
    // These options don't set a flag
    {"help",                      no_argument,       NULL, 'h'},
    {"duration",                  required_argument, NULL, 'd'},
    {"priority-queue",            required_argument, NULL, 'p'},
    {"linden",                    required_argument, NULL, 'L'},
    {"spray-list",                required_argument, NULL, 'l'},
    {"event-simulator",           required_argument, NULL, 'e'},
    {"initial-size",              required_argument, NULL, 'i'},
    {"num-threads",               required_argument, NULL, 'n'},
    {"range",                     required_argument, NULL, 'r'},
    {"seed",                      required_argument, NULL, 's'},
    {"update-rate",               required_argument, NULL, 'u'},
    {"elasticity",                required_argument, NULL, 'x'},
    {"nothing",                   required_argument, NULL, 'l'},
    {NULL, 0, NULL, 0}
  };

  sl_intset_t *set;
  pq_t *linden_set;
  int i, c, size;
  val_t last = 0; 
  val_t val = 0;
  pval_t pval = 0;
  unsigned long reads, effreads, updates, collisions, effupds, aborts, aborts_locked_read, aborts_locked_write,
                aborts_validate_read, aborts_validate_write, aborts_validate_commit, add, added, remove, removed,
                aborts_invalid_memory, aborts_double_write, max_retries, failures_because_contention, depdist;
  thread_data_t *data;
  pthread_t *threads;
  pthread_attr_t attr;
  barrier_t barrier;
  struct timeval start, end;
  struct timespec timeout;
  int duration = DEFAULT_DURATION;
  int initial = DEFAULT_INITIAL;
  int nb_threads = DEFAULT_NB_THREADS;
  long range = DEFAULT_RANGE;
  int seed = DEFAULT_SEED;
  int seed2 = DEFAULT_SEED;
  int update = DEFAULT_UPDATE;
  int unit_tx = DEFAULT_ELASTICITY;
  int alternate = DEFAULT_ALTERNATE;
  int pq = DEFAULT_PQ;
  int sl = DEFAULT_SL;
  int es = DEFAULT_ES;
  int lin = DEFAULT_LIN;
  int effective = DEFAULT_EFFECTIVE;
  sigset_t block_set;

  while(1) {
    i = 0;
    c = getopt_long(argc, argv, "hAplLe:f:d:i:n:r:s:u:x:l:", long_options, &i);

    if(c == -1)
      break;

    if(c == 0 && long_options[i].flag == 0)
      c = long_options[i].val;

    switch(c) {
      case 0:
        break;
      case 'h':
        printf("intset -- STM stress test "
            "(skip list)\n"
            "\n"
            "Usage:\n"
            "  intset [options...]\n"
            "\n"
            "Options:\n"
            "  -h, --help\n"
            "        Print this message\n"
            "  -A, --Alternate\n"
            "        Consecutive insert/remove target the same value\n"
            "  -l, --spray-list\n"
            "        Remove via delete_min operations using a spray list\n"
            "  -p, --priority-queue\n"
            "        Remove via delete_min operations using a skip list\n"
            "  -e, --event-simulator\n"
            "        Descrete event simulator experiment, parameter = dependency distance\n"
            "  -L, --linden\n"
            "        Use Linden's priority queue\n"
            "  -f, --effective <int>\n"
            "        update txs must effectively write (0=trial, 1=effective, default=" XSTR(DEFAULT_EFFECTIVE) ")\n"
            "  -d, --duration <int>\n"
            "        Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n"
            "  -i, --initial-size <int>\n"
            "        Number of elements to insert before test (default=" XSTR(DEFAULT_INITIAL) ")\n"
            "  -n, --num-threads <int>\n"
            "        Number of threads (default=" XSTR(DEFAULT_NB_THREADS) ")\n"
            "  -r, --range <int>\n"
            "        Range of integer values inserted in set (default=" XSTR(DEFAULT_RANGE) ")\n"
            "  -s, --seed <int>\n"
            "        RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n"
            "  -u, --update-rate <int>\n"
            "        Percentage of update transactions (default=" XSTR(DEFAULT_UPDATE) ")\n"
            "  -x, --elasticity (default=4)\n"
            "        Use elastic transactions\n"
            "        0 = non-protected,\n"
            "        1 = normal transaction,\n"
            "        2 = read elastic-tx,\n"
            "        3 = read/add elastic-tx,\n"
            "        4 = read/add/rem elastic-tx,\n"
            "        5 = fraser lock-free\n"
            );
        exit(0);
      case 'A':
        alternate = 1;
        break;
      case 'l':
        sl = 1;
        break;
      case 'p':
        pq = 1;
        break;
      case 'e':
        es = 1;
        depdist = atoi(optarg);
        break;
      case 'L':
        lin = 1;
        break;
      case 'f':
        effective = atoi(optarg);
        break;
      case 'd':
        duration = atoi(optarg);
        break;
      case 'i':
        initial = atoi(optarg);
        break;
      case 'n':
        nb_threads = atoi(optarg);
        break;
      case 'r':
        range = atol(optarg);
        break;
      case 's':
        seed = atoi(optarg);
        break;
      case 'u':
        update = atoi(optarg);
        break;
      case 'x':
        unit_tx = atoi(optarg);
        break;
      case '?':
        printf("Use -h or --help for help\n");
        exit(0);
      default:
        exit(1);
    }
  }

  assert(duration >= 0);
  assert(initial >= 0);
  assert(nb_threads > 0);
  assert(range > 0);
  assert(update >= 0 && update <= 100);

  // if (range < initial)
  // {
  range = 100000000;
  // }

  printf("Set type     : skip list\n");
  printf("Duration     : %d\n", duration);
  printf("Initial size : %u\n", initial);
  printf("Nb threads   : %d\n", nb_threads);
  printf("Value range  : %ld\n", range);
  printf("Seed         : %d\n", seed);
  printf("Update rate  : %d\n", update);
  printf("Elasticity   : %d\n", unit_tx);
  printf("Alternate    : %d\n", alternate);
  printf("Priority Q   : %d\n", pq);
  printf("Spray List   : %d\n", sl);
  printf("Linden       : %d\n", lin);
  printf("Efffective   : %d\n", effective);
  printf("Type sizes   : int=%d/long=%d/ptr=%d/word=%d\n",
      (int)sizeof(int),
      (int)sizeof(long),
      (int)sizeof(void *),
      (int)sizeof(uintptr_t));

  timeout.tv_sec = duration / 1000;
  timeout.tv_nsec = (duration % 1000) * 1000000;

  if ((data = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) {
    perror("malloc");
    exit(1);
  }
  if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) {
    perror("malloc");
    exit(1);
  }

  if (seed == 0)
    srand((int)time(0));
  else
    srand(seed);

  *levelmax = floor_log_2((unsigned int) initial);
  set = sl_set_new();

  /* stop = 0; */
  *running = 1;

  // Init STM 
  printf("Initializing STM\n");

  TM_STARTUP();

  // Populate set 
  printf("Adding %d entries to set\n", initial);
  i = 0;

  if (lin) {
    int offset = 32; // not sure what this does
     _init_gc_subsystem();
    linden_set = pq_init(offset);
  }

  if (es) { // event simulator has event ids 1..m
    // no timeout in ES, finishes when list is empty
    //   timeout.tv_sec = 0;
    //   timeout.tv_nsec = 0;

    if ((nb_deps = (int *)malloc(initial * sizeof(int))) == NULL) {
      perror("malloc");
      exit(1);
    }
    if ((deps = (val_t **)malloc(initial * sizeof(val_t*))) == NULL) {
      perror("malloc");
      exit(1);
    }
    while (i < initial)
    {
      if ((deps[i] = (val_t*)malloc(MAX_DEPS * sizeof(val_t))) == NULL) {
        perror("malloc");
        exit(1);
      }

      int num_deps = 0;
      nb_deps[i] = 0;

      if (lin) {
        insert(linden_set, i, i);
      } else {
        sl_add(set, (val_t)i, 0);
      }

      while (i < initial-1 && num_deps < MAX_DEPS &&
          rand_range_re(NULL, 3) % 2) { // Add geometrically distributed # of deps TODO: parametrize '2'
        val_t dep = ((val_t)i)+1;
        int dep_var = sqrt(depdist);
        dep += depdist + rand_range_re(NULL,2*dep_var) - dep_var;
        if (dep >= initial) dep = initial-1;
        //       while (dep < initial-1 && rand_range_re(NULL, 11) % 10) { // dep should be i+GEO(10) TODO: parametrize '10'
        //         dep++;
        //       }
        deps[i][num_deps] = dep;
        num_deps++;
      }
      nb_deps[i] = num_deps;
      if (num_deps < MAX_DEPS) {
        deps[i][num_deps] = -1; // marks last dep
      }

      i++;
    }
  } else if (lin) {
    while (i < initial)
    {
#ifdef DISTRIBUTION_EXPERIMENT
      pval = i;
#else
      pval = rand_range_re(NULL, range);
#endif
      insert(linden_set, pval, pval);
      last = pval;
      i++;
    }
  } else {
    while (i < initial)
    {
#ifdef DISTRIBUTION_EXPERIMENT
      val = i;
#else
      val = rand_range_re(NULL, range);
#endif
      if (sl_add(set, val, 0))
      {
        last = val;
        i++;
      }
    }
  }

#ifdef PRINT_LIST
  print_skiplist(set);
#endif


  size = sl_set_size(set);
  printf("Set size     : %d\n", size);
  printf("Level max    : %d\n", *levelmax);

  // Access set from all threads 
  barrier_init(&barrier, nb_threads + 1);
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  printf("Creating threads: ");
  for (i = 0; i < nb_threads; i++)
  {
    printf("%d, ", i);
    data[i].first = last;
    data[i].range = range;
    data[i].update = update;
    data[i].unit_tx = unit_tx;
    data[i].alternate = alternate;
    data[i].pq = pq;
    data[i].sl = sl;
    data[i].es = es;
    data[i].effective = effective;
    data[i].first_remove = -1;
    data[i].nb_collisions = 0;
    data[i].nb_add = 0;
    data[i].nb_clean = 0;
    data[i].nb_added = 0;
    data[i].nb_remove = 0;
    data[i].nb_removed = 0;
    data[i].nb_contains = 0;
    data[i].nb_found = 0;
    data[i].nb_aborts = 0;
    data[i].nb_aborts_locked_read = 0;
    data[i].nb_aborts_locked_write = 0;
    data[i].nb_aborts_validate_read = 0;
    data[i].nb_aborts_validate_write = 0;
    data[i].nb_aborts_validate_commit = 0;
    data[i].nb_aborts_invalid_memory = 0;
    data[i].nb_aborts_double_write = 0;
    data[i].max_retries = 0;
    data[i].nb_threads = nb_threads;
    data[i].seed = rand();
    data[i].seed2 = rand();
    data[i].set = set;
    data[i].barrier = &barrier;
    data[i].failures_because_contention = 0;
    data[i].id = i;

    /* LINDEN */
    data[i].lin = lin;
    data[i].linden_set = linden_set;

    if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) {
      fprintf(stderr, "Error creating thread\n");
      exit(1);
    }
  }
  pthread_attr_destroy(&attr);

  // Catch some signals 
  if (signal(SIGHUP, catcher) == SIG_ERR ||
      //signal(SIGINT, catcher) == SIG_ERR ||
      signal(SIGTERM, catcher) == SIG_ERR) {
    perror("signal");
    exit(1);
  }

  // Start threads 
  barrier_cross(&barrier);

  printf("STARTING...\n");
  gettimeofday(&start, NULL);

#ifndef DISTRIBUTION_EXPERIMENT // don't sleep if doing distro experiment
  if (duration > 0) {
    nanosleep(&timeout, NULL);
  } else {
    sigemptyset(&block_set);
    sigsuspend(&block_set);
  }
#endif

  /* AO_store_full(&stop, 1); */
  *running = 0;

  // if (!es) {
  gettimeofday(&end, NULL);
  // }
  printf("STOPPING...\n");

  // Wait for thread completion 
  for (i = 0; i < nb_threads; i++) {
    if (pthread_join(threads[i], NULL) != 0) {
      fprintf(stderr, "Error waiting for thread completion\n");
      exit(1);
    }
  }

  // if (es) {
  //   gettimeofday(&end, NULL); // time when all threads finish
  // }

  printf ("duration = %d\n", duration);
  duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000);
  printf ("duration = %d\n", duration);
  aborts = 0;
  aborts_locked_read = 0;
  aborts_locked_write = 0;
  aborts_validate_read = 0;
  aborts_validate_write = 0;
  aborts_validate_commit = 0;
  aborts_invalid_memory = 0;
  aborts_double_write = 0;
  failures_because_contention = 0;
  reads = 0;
  effreads = 0;
  updates = 0;
  collisions = 0;
  add = 0;
  added = 0;
  remove = 0;
  removed = 0;
  effupds = 0;
  max_retries = 0;
  for (i = 0; i < nb_threads; i++) {
    printf("Thread %d\n", i);
    printf("  #add        : %lu\n", data[i].nb_add);
    printf("    #added    : %lu\n", data[i].nb_added);
    printf("  #remove     : %lu\n", data[i].nb_remove);
    printf("    #removed  : %lu\n", data[i].nb_removed);
    printf("    #cleaned  : %lu\n", data[i].nb_clean);
    printf("first remove  : %d\n", data[i].first_remove);
    printf(" #collisions  : %lu\n", data[i].nb_collisions);
    printf("  #contains   : %lu\n", data[i].nb_contains);
    printf("  #found      : %lu\n", data[i].nb_found);
    printf("  #aborts     : %lu\n", data[i].nb_aborts);
    printf("    #lock-r   : %lu\n", data[i].nb_aborts_locked_read);
    printf("    #lock-w   : %lu\n", data[i].nb_aborts_locked_write);
    printf("    #val-r    : %lu\n", data[i].nb_aborts_validate_read);
    printf("    #val-w    : %lu\n", data[i].nb_aborts_validate_write);
    printf("    #val-c    : %lu\n", data[i].nb_aborts_validate_commit);
    printf("    #inv-mem  : %lu\n", data[i].nb_aborts_invalid_memory);
    printf("    #dup-w    : %lu\n", data[i].nb_aborts_double_write);
    printf("    #failures : %lu\n", data[i].failures_because_contention);
    printf("  Max retries : %lu\n", data[i].max_retries);
    aborts += data[i].nb_aborts;
    aborts_locked_read += data[i].nb_aborts_locked_read;
    aborts_locked_write += data[i].nb_aborts_locked_write;
    aborts_validate_read += data[i].nb_aborts_validate_read;
    aborts_validate_write += data[i].nb_aborts_validate_write;
    aborts_validate_commit += data[i].nb_aborts_validate_commit;
    aborts_invalid_memory += data[i].nb_aborts_invalid_memory;
    aborts_double_write += data[i].nb_aborts_double_write;
    failures_because_contention += data[i].failures_because_contention;
    reads += data[i].nb_contains;
    effreads += data[i].nb_contains + 
      (data[i].nb_add - data[i].nb_added) + 
      (data[i].nb_remove - data[i].nb_removed); 
    updates += (data[i].nb_add + data[i].nb_remove);
    collisions += data[i].nb_collisions;
    add += data[i].nb_add;
    added += data[i].nb_added;
    remove += data[i].nb_remove;
    removed += data[i].nb_removed;
    effupds += data[i].nb_removed + data[i].nb_added; 
    size += data[i].nb_added - data[i].nb_removed;
    if (max_retries < data[i].max_retries)
      max_retries = data[i].max_retries;
  }
  printf("Set size      : %d (expected: %d)\n", sl_set_size(set), size);
  printf("Duration      : %d (ms)\n", duration);
  printf("#txs          : %lu (%f / s)\n", reads + updates, (reads + updates) * 1000.0 / duration);

  printf("#read txs     : ");
  if (effective) {
    printf("%lu (%f / s)\n", effreads, effreads * 1000.0 / duration);
    printf("  #contains   : %lu (%f / s)\n", reads, reads * 1000.0 / duration);
  } else printf("%lu (%f / s)\n", reads, reads * 1000.0 / duration);

  printf("#eff. upd rate: %f \n", 100.0 * effupds / (effupds + effreads));

  printf("#update txs   : ");
  if (effective) {
    printf("%lu (%f / s)\n", effupds, effupds * 1000.0 / duration);
    printf("  #upd trials : %lu (%f / s)\n", updates, updates * 1000.0 / 
        duration);
  } else printf("%lu (%f / s)\n", updates, updates * 1000.0 / duration);

  printf("#total_remove : %lu\n", remove);
  printf("#total_removed: %lu\n", removed);
  printf("#total_add    : %lu\n", add);
  printf("#total_added  : %lu\n", added);
  printf("#net (rem-add): %lu\n", removed-added);
  printf("#total_collide: %lu\n", collisions);
  printf("#norm_collide : %f\n", ((double)collisions)/removed);


  printf("#aborts       : %lu (%f / s)\n", aborts, aborts * 1000.0 / duration);
  printf("  #lock-r     : %lu (%f / s)\n", aborts_locked_read, aborts_locked_read * 1000.0 / duration);
  printf("  #lock-w     : %lu (%f / s)\n", aborts_locked_write, aborts_locked_write * 1000.0 / duration);
  printf("  #val-r      : %lu (%f / s)\n", aborts_validate_read, aborts_validate_read * 1000.0 / duration);
  printf("  #val-w      : %lu (%f / s)\n", aborts_validate_write, aborts_validate_write * 1000.0 / duration);
  printf("  #val-c      : %lu (%f / s)\n", aborts_validate_commit, aborts_validate_commit * 1000.0 / duration);
  printf("  #inv-mem    : %lu (%f / s)\n", aborts_invalid_memory, aborts_invalid_memory * 1000.0 / duration);
  printf("  #dup-w      : %lu (%f / s)\n", aborts_double_write, aborts_double_write * 1000.0 / duration);
  printf("  #failures   : %lu\n",  failures_because_contention);
  printf("Max retries   : %lu\n", max_retries);

#ifdef PRINT_END
  print_skiplist(set);
#endif

#ifdef PAPI
  long total_L1_miss = 0;
  unsigned k = 0;
  for (k = 0; k < nb_threads; k++) {
    total_L1_miss += g_values[k][0];
    //printf("[Thread %d] L1_DCM: %lld\n", i, g_values[i][0]);
    //printf("[Thread %d] L2_DCM: %lld\n", i, g_values[i][1]);
  }
  printf("\n#L1 Cache Misses: %lld\n", total_L1_miss);
  printf("#Normalized Cache Misses: %f\n", ((double)total_L1_miss)/(reads+updates));
#endif

  // Delete set 
  sl_set_delete(set);

  // Cleanup STM 
  TM_SHUTDOWN();

  free(threads);
  free(data);

  return 0;
}
Пример #30
0
int main(int argc, char **argv)
{
	struct option long_options[] = {
		// These options don't set a flag
		{"help",                      no_argument,       NULL, 'h'},
		{"duration",                  required_argument, NULL, 'd'},
		{"initial-size",              required_argument, NULL, 'i'},
		{"thread-num",                required_argument, NULL, 't'},
		{"range",                     required_argument, NULL, 'r'},
		{"seed",                      required_argument, NULL, 'S'},
		{"update-rate",               required_argument, NULL, 'u'},
		{"elasticity",                required_argument, NULL, 'x'},
		{NULL, 0, NULL, 0}
	};
	
	avl_intset_t *set;
	int i, j, c, size, tree_size;
	val_t last = 0; 
	val_t val = 0;
	unsigned long reads, effreads, updates, effupds, aborts, aborts_locked_read, aborts_locked_write,
	aborts_validate_read, aborts_validate_write, aborts_validate_commit,
	aborts_invalid_memory, aborts_double_write, max_retries, failures_because_contention;
	thread_data_t *data;
	maintenance_thread_data_t *maintenance_data;
	pthread_t *threads;
	pthread_t *maintenance_threads;
	pthread_attr_t attr;
	barrier_t barrier;
	struct timeval start, end;
	struct timespec timeout;
	int duration = DEFAULT_DURATION;
	int initial = DEFAULT_INITIAL;
	int nb_threads = DEFAULT_NB_THREADS;
	int nb_maintenance_threads = DEFAULT_NB_MAINTENANCE_THREADS;
	long range = DEFAULT_RANGE;
	int seed = DEFAULT_SEED;
	int update = DEFAULT_UPDATE;
	int unit_tx = DEFAULT_ELASTICITY;
	int alternate = DEFAULT_ALTERNATE;
	int effective = DEFAULT_EFFECTIVE;
	sigset_t block_set;
	
	while(1) {
		i = 0;
		c = getopt_long(argc, argv, "hAf:d:i:t:r:S:u:x:"
										, long_options, &i);
		
		if(c == -1)
			break;
		
		if(c == 0 && long_options[i].flag == 0)
			c = long_options[i].val;
		
		switch(c) {
				case 0:
					break;
				case 'h':
					printf("intset -- STM stress test "
								 "(avltree)\n"
								 "\n"
								 "Usage:\n"
								 "  intset [options...]\n"
								 "\n"
								 "Options:\n"
								 "  -h, --help\n"
								 "        Print this message\n"
								 "  -A, --Alternate\n"
								 "        Consecutive insert/remove target the same value\n"
								 "  -f, --effective <int>\n"
								 "        update txs must effectively write (0=trial, 1=effective, default=" XSTR(DEFAULT_EFFECTIVE) ")\n"
								 "  -d, --duration <int>\n"
								 "        Test duration in milliseconds (0=infinite, default=" XSTR(DEFAULT_DURATION) ")\n"
								 "  -i, --initial-size <int>\n"
								 "        Number of elements to insert before test (default=" XSTR(DEFAULT_INITIAL) ")\n"
								 "  -t, --thread-num <int>\n"
								 "        Number of threads (default=" XSTR(DEFAULT_NB_THREADS) ")\n"
								 "  -r, --range <int>\n"
								 "        Range of integer values inserted in set (default=" XSTR(DEFAULT_RANGE) ")\n"
								 "  -S, --seed <int>\n"
								 "        RNG seed (0=time-based, default=" XSTR(DEFAULT_SEED) ")\n"
								 "  -u, --update-rate <int>\n"
								 "        Percentage of update transactions (default=" XSTR(DEFAULT_UPDATE) ")\n"
								 "  -x, --elasticity (default=4)\n"
								 "        Use elastic transactions\n"
								 "        0 = non-protected,\n"
								 "        1 = normal transaction,\n"
								 "        2 = read elastic-tx,\n"
								 "        3 = read/add elastic-tx,\n"
								 "        4 = read/add/rem elastic-tx,\n"
								 "        5 = fraser lock-free\n"
								 );
					exit(0);
				case 'A':
					alternate = 1;
					break;
				case 'f':
					effective = atoi(optarg);
					break;
				case 'd':
					duration = atoi(optarg);
					break;
				case 'i':
					initial = atoi(optarg);
					break;
				case 't':
					nb_threads = atoi(optarg);
					break;
				case 'r':
					range = atol(optarg);
					break;
				case 'S':
					seed = atoi(optarg);
					break;
				case 'u':
					update = atoi(optarg);
					break;
				case 'x':
					unit_tx = atoi(optarg);
					break;
				case '?':
					printf("Use -h or --help for help\n");
					exit(0);
				default:
					exit(1);
		}
	}
	
	assert(duration >= 0);
	assert(initial >= 0);
	assert(nb_threads > 0);
	assert(range > 0 && range >= initial);
	assert(update >= 0 && update <= 100);
	
	printf("Set type     : avltree\n");
	printf("Duration     : %d\n", duration);
	printf("Initial size : %u\n", initial);
	printf("Nb threads   : %d\n", nb_threads);
	printf("Nb mt threads: %d\n", nb_maintenance_threads);
	printf("Value range  : %ld\n", range);
	printf("Seed         : %d\n", seed);
	printf("Update rate  : %d\n", update);
	printf("Elasticity   : %d\n", unit_tx);
	printf("Alternate    : %d\n", alternate);
	printf("Efffective   : %d\n", effective);
	printf("Type sizes   : int=%d/long=%d/ptr=%d/word=%d\n",
				 (int)sizeof(int),
				 (int)sizeof(long),
				 (int)sizeof(void *),
				 (int)sizeof(uintptr_t));
	
	timeout.tv_sec = duration / 1000;
	timeout.tv_nsec = (duration % 1000) * 1000000;
	
	if ((data = (thread_data_t *)malloc(nb_threads * sizeof(thread_data_t))) == NULL) {
		perror("malloc");
		exit(1);
	}
	if ((threads = (pthread_t *)malloc(nb_threads * sizeof(pthread_t))) == NULL) {
		perror("malloc");
		exit(1);
	}


	if ((maintenance_data = (maintenance_thread_data_t *)malloc(nb_maintenance_threads * sizeof(maintenance_thread_data_t))) == NULL) {
		perror("malloc");
		exit(1);
	}
	if ((maintenance_threads = (pthread_t *)malloc(nb_maintenance_threads * sizeof(pthread_t))) == NULL) {
		perror("malloc");
		exit(1);
	}


	
	if (seed == 0)
		srand((int)time(0));
	else
		srand(seed);
	
	//levelmax = floor_log_2((unsigned int) initial);

	//set = avl_set_new();
	set = avl_set_new_alloc(0, nb_threads);
	//set->stop = &stop;
	//#endif
	stop = 0;
	
	global_seed = rand();
#ifdef TLS
	rng_seed = &global_seed;
#else /* ! TLS */
	if (pthread_key_create(&rng_seed_key, NULL) != 0) {
		fprintf(stderr, "Error creating thread local\n");
		exit(1);
	}
	pthread_setspecific(rng_seed_key, &global_seed);
#endif /* ! TLS */
	
	// Init STM 
	printf("Initializing STM\n");
	
	TM_STARTUP();
	
	// Populate set 
	printf("Adding %d entries to set\n", initial);
	i = 0;
	
	while (i < initial) {
		val = rand_range_re(&global_seed, range);
		//printf("Adding %d\n", val);
		if (avl_add(set, val, 0, 0) > 0) {
		  //printf("Added %d\n", val);
		  //print_avltree(set);

			last = val;
			i++;
		}
	}
	size = avl_set_size(set);
	tree_size = avl_tree_size(set);
	printf("Set size     : %d\n", size);
	printf("Tree size     : %d\n", tree_size);
	//printf("Level max    : %d\n", levelmax);
	
	// Access set from all threads 
	barrier_init(&barrier, nb_threads + nb_maintenance_threads + 1);
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
	for (i = 0; i < nb_threads; i++) {
		printf("Creating thread %d\n", i);
		data[i].id = i;
		data[i].first = last;
		data[i].range = range;
		data[i].update = update;
		data[i].unit_tx = unit_tx;
		data[i].alternate = alternate;
		data[i].effective = effective;
		data[i].nb_modifications = 0;
		data[i].nb_add = 0;
		data[i].nb_added = 0;
		data[i].nb_remove = 0;
		data[i].nb_removed = 0;
		data[i].nb_contains = 0;
		data[i].nb_found = 0;
		data[i].nb_aborts = 0;
		data[i].nb_aborts_locked_read = 0;
		data[i].nb_aborts_locked_write = 0;
		data[i].nb_aborts_validate_read = 0;
		data[i].nb_aborts_validate_write = 0;
		data[i].nb_aborts_validate_commit = 0;
		data[i].nb_aborts_invalid_memory = 0;
		data[i].nb_aborts_double_write = 0;
		data[i].max_retries = 0;
		data[i].seed = rand();
		data[i].set = set;
		data[i].barrier = &barrier;
		data[i].failures_because_contention = 0;
		if (pthread_create(&threads[i], &attr, test, (void *)(&data[i])) != 0) {
			fprintf(stderr, "Error creating thread\n");
			exit(1);
		}
	}


	for (i = 0; i < nb_maintenance_threads; i++) {
	        maintenance_data[i].nb_maint = nb_maintenance_threads;
		maintenance_data[i].id = i;
		maintenance_data[i].nb_removed = 0;
		maintenance_data[i].nb_rotated = 0;
		maintenance_data[i].nb_suc_rotated = 0;
		maintenance_data[i].nb_propagated = 0;
		maintenance_data[i].nb_suc_propagated = 0;
		maintenance_data[i].nb_aborts = 0;
		maintenance_data[i].nb_aborts_locked_read = 0;
		maintenance_data[i].nb_aborts_locked_write = 0;
		maintenance_data[i].nb_aborts_validate_read = 0;
		maintenance_data[i].nb_aborts_validate_write = 0;
		maintenance_data[i].nb_aborts_validate_commit = 0;
		maintenance_data[i].nb_aborts_invalid_memory = 0;
		maintenance_data[i].nb_aborts_double_write = 0;
		maintenance_data[i].max_retries = 0;
		maintenance_data[i].t_data = data;
		maintenance_data[i].nb_threads = nb_threads;

		maintenance_data[i].set = set;
		maintenance_data[i].barrier = &barrier;

		if ((maintenance_data[i].t_nb_trans = (unsigned long *)malloc(nb_threads * sizeof(unsigned long))) == NULL) {
		  perror("malloc");
		  exit(1);
		}
		for(j = 0; j < nb_threads; j++) {
		  maintenance_data[i].t_nb_trans[j] = 0;
		}
		if ((maintenance_data[i].t_nb_trans_old = (unsigned long *)malloc(nb_threads * sizeof(unsigned long))) == NULL) {
		  perror("malloc");
		  exit(1);
		}
		for(j = 0; j < nb_threads; j++) {
		  maintenance_data[i].t_nb_trans_old[j] = 0;
		}

		printf("Creating maintenance thread %d\n", i);
		if (pthread_create(&maintenance_threads[i], &attr, test_maintenance, (void *)(&maintenance_data[i])) != 0) {
			fprintf(stderr, "Error creating thread\n");
			exit(1);
		}
	}

	pthread_attr_destroy(&attr);


	
	// Catch some signals 
	if (signal(SIGHUP, catcher) == SIG_ERR ||
			//signal(SIGINT, catcher) == SIG_ERR ||
			signal(SIGTERM, catcher) == SIG_ERR) {
		perror("signal");
		exit(1);
	}
	
	// Start threads 
	barrier_cross(&barrier);
	
	printf("STARTING...\n");
	gettimeofday(&start, NULL);
	if (duration > 0) {
		nanosleep(&timeout, NULL);
	} else {
		sigemptyset(&block_set);
		sigsuspend(&block_set);
	}
	
#ifdef ICC
	stop = 1;
#else	
	AO_store_full(&stop, 1);
#endif /* ICC */
	
	gettimeofday(&end, NULL);
	printf("STOPPING...\n");
	
	// Wait for thread completion 
	for (i = 0; i < nb_threads; i++) {
		if (pthread_join(threads[i], NULL) != 0) {
			fprintf(stderr, "Error waiting for thread completion\n");
			exit(1);
		}
	}


	// Wait for maintenance thread completion 
	for (i = 0; i < nb_maintenance_threads; i++) {
		if (pthread_join(maintenance_threads[i], NULL) != 0) {
			fprintf(stderr, "Error waiting for maintenance thread completion\n");
			exit(1);
		}
	}


	
	duration = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000);
	aborts = 0;
	aborts_locked_read = 0;
	aborts_locked_write = 0;
	aborts_validate_read = 0;
	aborts_validate_write = 0;
	aborts_validate_commit = 0;
	aborts_invalid_memory = 0;
	aborts_double_write = 0;
	failures_because_contention = 0;
	reads = 0;
	effreads = 0;
	updates = 0;
	effupds = 0;
	max_retries = 0;
	for (i = 0; i < nb_threads; i++) {
		printf("Thread %d\n", i);
		printf("  #add        : %lu\n", data[i].nb_add);
		printf("    #added    : %lu\n", data[i].nb_added);
		printf("  #remove     : %lu\n", data[i].nb_remove);
		printf("    #removed  : %lu\n", data[i].nb_removed);
		printf("  #contains   : %lu\n", data[i].nb_contains);
		printf("  #found      : %lu\n", data[i].nb_found);
		printf("  #aborts     : %lu\n", data[i].nb_aborts);
		printf("    #lock-r   : %lu\n", data[i].nb_aborts_locked_read);
		printf("    #lock-w   : %lu\n", data[i].nb_aborts_locked_write);
		printf("    #val-r    : %lu\n", data[i].nb_aborts_validate_read);
		printf("    #val-w    : %lu\n", data[i].nb_aborts_validate_write);
		printf("    #val-c    : %lu\n", data[i].nb_aborts_validate_commit);
		printf("    #inv-mem  : %lu\n", data[i].nb_aborts_invalid_memory);
		printf("    #dup-w    : %lu\n", data[i].nb_aborts_double_write);
		printf("    #failures : %lu\n", data[i].failures_because_contention);
		printf("  Max retries : %lu\n", data[i].max_retries);

		printf("  #set read trans reads: %lu\n", data[i].set_read_reads);
		printf("  #set write trans reads: %lu\n", data[i].set_write_reads);
		printf("  #set write trans writes: %lu\n", data[i].set_write_writes);
		printf("  #set trans reads: %lu\n", data[i].set_reads);
		printf("  #set trans writes: %lu\n", data[i].set_writes);
		printf("  set max reads: %lu\n", data[i].set_max_reads);
		printf("  set max writes: %lu\n", data[i].set_max_writes);

		printf("  #read trans reads: %lu\n", data[i].read_reads);
		printf("  #write trans reads: %lu\n", data[i].write_reads);
		printf("  #write trans writes: %lu\n", data[i].write_writes);
		printf("  #trans reads: %lu\n", data[i].reads);
		printf("  #trans writes: %lu\n", data[i].writes);
		printf("  max reads: %lu\n", data[i].max_reads);
		printf("  max writes: %lu\n", data[i].max_writes);
		aborts += data[i].nb_aborts;
		aborts_locked_read += data[i].nb_aborts_locked_read;
		aborts_locked_write += data[i].nb_aborts_locked_write;
		aborts_validate_read += data[i].nb_aborts_validate_read;
		aborts_validate_write += data[i].nb_aborts_validate_write;
		aborts_validate_commit += data[i].nb_aborts_validate_commit;
		aborts_invalid_memory += data[i].nb_aborts_invalid_memory;
		aborts_double_write += data[i].nb_aborts_double_write;
		failures_because_contention += data[i].failures_because_contention;
		reads += data[i].nb_contains;
		effreads += data[i].nb_contains + 
		(data[i].nb_add - data[i].nb_added) + 
		(data[i].nb_remove - data[i].nb_removed); 
		updates += (data[i].nb_add + data[i].nb_remove);
		effupds += data[i].nb_removed + data[i].nb_added; 
		size += data[i].nb_added - data[i].nb_removed;
		if (max_retries < data[i].max_retries)
			max_retries = data[i].max_retries;
	}


	for (i = 0; i < nb_maintenance_threads; i++) {
		printf("Maintenance thread %d\n", i);
		printf("  #removed %lu\n", set->nb_removed);
		printf("  #rotated %lu\n", set->nb_rotated);
		printf("  #rotated sucs %lu\n", set->nb_suc_rotated);
		printf("  #propogated %lu\n", set->nb_propogated);
		printf("  #propogated sucs %lu\n", set->nb_suc_propogated);
		printf("  #aborts     : %lu\n", maintenance_data[i].nb_aborts);
		printf("    #lock-r   : %lu\n", maintenance_data[i].nb_aborts_locked_read);
		printf("    #lock-w   : %lu\n", maintenance_data[i].nb_aborts_locked_write);
		printf("    #val-r    : %lu\n", maintenance_data[i].nb_aborts_validate_read);
		printf("    #val-w    : %lu\n", maintenance_data[i].nb_aborts_validate_write);
		printf("    #val-c    : %lu\n", maintenance_data[i].nb_aborts_validate_commit);
		printf("    #inv-mem  : %lu\n", maintenance_data[i].nb_aborts_invalid_memory);
		printf("    #dup-w    : %lu\n", maintenance_data[i].nb_aborts_double_write);
		//printf("    #failures : %lu\n", maintenance_data[i].failures_because_contention);
		printf("  Max retries : %lu\n", maintenance_data[i].max_retries);
	}


	printf("Set size      : %d (expected: %d)\n", avl_set_size(set), size);
	printf("Tree size      : %d\n", avl_tree_size(set));
	printf("Duration      : %d (ms)\n", duration);
	printf("#txs          : %lu (%f / s)\n", reads + updates, (reads + updates) * 1000.0 / duration);
	
	printf("#read txs     : ");
	if (effective) {
		printf("%lu (%f / s)\n", effreads, effreads * 1000.0 / duration);
		printf("  #contains   : %lu (%f / s)\n", reads, reads * 1000.0 / duration);
	} else printf("%lu (%f / s)\n", reads, reads * 1000.0 / duration);
	
	printf("#eff. upd rate: %f \n", 100.0 * effupds / (effupds + effreads));
	
	printf("#update txs   : ");
	if (effective) {
		printf("%lu (%f / s)\n", effupds, effupds * 1000.0 / duration);
		printf("  #upd trials : %lu (%f / s)\n", updates, updates * 1000.0 / 
					 duration);
	} else printf("%lu (%f / s)\n", updates, updates * 1000.0 / duration);
	
	printf("#aborts       : %lu (%f / s)\n", aborts, aborts * 1000.0 / duration);
	printf("  #lock-r     : %lu (%f / s)\n", aborts_locked_read, aborts_locked_read * 1000.0 / duration);
	printf("  #lock-w     : %lu (%f / s)\n", aborts_locked_write, aborts_locked_write * 1000.0 / duration);
	printf("  #val-r      : %lu (%f / s)\n", aborts_validate_read, aborts_validate_read * 1000.0 / duration);
	printf("  #val-w      : %lu (%f / s)\n", aborts_validate_write, aborts_validate_write * 1000.0 / duration);
	printf("  #val-c      : %lu (%f / s)\n", aborts_validate_commit, aborts_validate_commit * 1000.0 / duration);
	printf("  #inv-mem    : %lu (%f / s)\n", aborts_invalid_memory, aborts_invalid_memory * 1000.0 / duration);
	printf("  #dup-w      : %lu (%f / s)\n", aborts_double_write, aborts_double_write * 1000.0 / duration);
	printf("  #failures   : %lu\n",  failures_because_contention);
	printf("Max retries   : %lu\n", max_retries);
	

	//print_avltree(set);
	// Delete set 
        avl_set_delete(set);
	
	// Cleanup STM 
	TM_SHUTDOWN();
	
#ifndef TLS
	pthread_key_delete(rng_seed_key);
#endif /* ! TLS */
	
	free(threads);
	free(data);

	free(maintenance_threads);
	free(maintenance_data);
	
	return 0;
}