root/usr/src/test/os-tests/tests/sigqueue/sigqueue_queue_size.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 2013 David Hoeppner.  All rights reserved.
 */

/*
 * Queue maximum number of signals and test if we can queue more signals then
 * allowed.
 */

#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

#define SIGQUEUE_SIGNAL         SIGRTMIN        /* Signal used for testing */

int nreceived = 0;

static void
test_start(const char *test_name, const char *format, ...)
{
        va_list args;

        (void) printf("TEST STARTING %s: ", test_name);

        va_start(args, format);
        (void) vprintf(format, args);
        va_end(args);
        (void) fflush(stdout);
}

static void
test_failed(const char *test_name, const char *format, ...)
{
        va_list args;

        (void) printf("TEST FAILED %s: ", test_name);

        va_start(args, format);
        (void) vprintf(format, args);
        va_end(args);

        (void) exit(-1);
}

static void
test_passed(const char *test_name)
{
        (void) printf("TEST PASS: %s\n", test_name);
        (void) fflush(stdout);
}

/* ARGSUSED */
static void
maximum_test_handler(int signal, siginfo_t *siginfo, void *context)
{
        nreceived++;
}

static void
sigqueue_maximum_test(void)
{
        const char *test_name = __func__;
        struct sigaction action;
        long sigqueue_max, i;
        pid_t pid;
        union sigval value;
        int error;

        test_start(test_name, "queue maximum number of signals\n");

        /*
         * Get the maximum size of the queue.
         */
        sigqueue_max = sysconf(_SC_SIGQUEUE_MAX);
        if (sigqueue_max == -1) {
                test_failed(test_name, "sysconf\n");
        }

        /*
         * Put the signal on hold.
         */
        error = sighold(SIGQUEUE_SIGNAL);
        if (error == -1) {
                test_failed(test_name, "sighold\n");
        }

        pid = getpid();
        value.sival_int = 0;

        action.sa_flags = SA_SIGINFO;
        action.sa_sigaction = maximum_test_handler;

        error = sigemptyset(&action.sa_mask);
        if (error == -1) {
                test_failed(test_name, "sigemptyset\n");
        }

        /*
         * Set signal handler.
         */
        error = sigaction(SIGQUEUE_SIGNAL, &action, 0);
        if (error == -1) {
                test_failed(test_name, "sigaction\n");
        }

        /*
         * Fill the signal queue to the maximum.
         */
        for (i = 0; i < sigqueue_max; i++) {
                error = sigqueue(pid, SIGQUEUE_SIGNAL, value);
                if (error == -1) {
                        test_failed(test_name, "sigqueue\n");
                }
        }

        /*
         * Send a further signal and test if we get the expected
         * error.
         */
        error = sigqueue(pid, SIGQUEUE_SIGNAL, value);
        if (error != -1) {
                test_failed(test_name, "sigqueue\n");
        }

        /*
         * Unblock the signals and check if we received all messages
         * from the signal queue.
         */
        error = sigrelse(SIGQUEUE_SIGNAL);
        if (error == -1) {
                test_failed(test_name, "sigrelse\n");
        }

        if (nreceived != sigqueue_max) {
                test_failed(test_name, "nreceived != sigqueue_max\n");
        }

        test_passed(test_name);
}

static void
run_tests(void)
{
        sigqueue_maximum_test();
}

/* ARGSUSED */
int
main(int argc, char *argv[])
{
        run_tests();

        return (EXIT_SUCCESS);
}