root/usr/src/test/os-tests/tests/timer/timer_limit.c
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2016 Joyent, Inc.
 */

#include <assert.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <limits.h>
#include <sys/sysconfig.h>
#include <sys/sysmacros.h>

/* Need direct access to _sysconfig to query NCPU */
extern long _sysconfig(int);


static int
mktimer(timer_t *timer)
{
        struct sigevent sev;
        sev.sigev_notify = SIGEV_SIGNAL;
        sev.sigev_signo = SIGRTMIN;
        sev.sigev_value.sival_ptr = timer;

        return (timer_create(CLOCK_MONOTONIC, &sev, timer));
}

int
main(void)
{
        long ncpu;
        size_t limit;
        timer_t *timers, timer_overage;

        /* Query NCPU with private sysconfig param */
        ncpu = _sysconfig(_CONFIG_NPROC_NCPU);
        assert(ncpu > 0 && ncpu < INT32_MAX);

        /* Current specified limit is 4 * NCPU */
        limit = 4 * ncpu;
        timers = calloc(limit + 1, sizeof (timer_t));
        if (timers == NULL)
                err(EXIT_FAILURE, "failed to allocate %zu timers", limit + 1);

        /* Slowly walk up to the limit doing creations/deletions */
        for (int i = 1; i <= limit; i = MIN(limit, i*2)) {
                for (int j = 0; j < i; j++) {
                        assert(mktimer(&timers[j]) == 0);
                }

                /*
                 * Attempt to allocate one additional timer if we've reached
                 * the assumed limit.
                 */
                if (i == limit) {
                        assert(mktimer(&timer_overage) == -1);
                }

                for (int j = 0; j < i; j++) {
                        assert(timer_delete(timers[j]) == 0);
                }

                /* Bail out if we've finished at the limit */
                if (i == limit)
                        break;
        }


        return (0);
}