/*
 * Copyright (c) 2002, Intel Corporation. All rights reserved.
 * Created by:  salwan.searty REMOVE-THIS AT intel DOT com
 * This file is licensed under the GPL license.  For the full content
 * of this license, see the COPYING file at the top level of this
 * source tree.

 This program verifies that the pthread_kill() function requests from the
 kernel to deliver a specified signal to a specified thread.

 Using two global values of sem1 (INTHREAD and INMAIN), we are going to
 control  when we want execution to be in main() and when we want
 execution to be a_thread_func(). When the main() function sets sem1 to
 INTHREAD and keeps looping until sem1 gets changed back to INMAIN, the
 a_thread_func() will be exclusively running. Similarly, when the
 a_thread_func() sets sem1 to INMAIN and keeps looping until sem1 gets
 changed back to INTHREAD, the main() function will be exclusively
 running.

 Steps:
 1. From the main() function, create a new thread. Using the above
    methodology, let the new thread run "exclusively."
 2. Inside the new thread, prepare for catching the signal indicated by
    SIGTOTEST, and calling a handler that sets handler_called to 1. Now
    let the main() thread run "exclusively".
 3. Have main() send the signal indicated by SIGTOTEST to the new thread,
    using pthread_kill(). Let the new thread continue running,
    and from the main function, wait until handler_called is set to
    something other than 0.
 4. In the new thread, if the handler wasn't called for more than 5
    seconds, then set handler_called to -1, otherwise set it to 1.
 5. In either case, the main() function will continue execution and return
    a PTS_PASS if handler_called was 1, and a PTS_FAIL if handler_called
    was -1.
 */

#include <pthread.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include "posixtest.h"

#define INTHREAD 0
#define INMAIN 1
#define SIGTOTEST SIGABRT

static int sem1;			/* Manual semaphore */
static volatile int handler_called;

static void handler()
{
	printf("signal was called\n");
	handler_called = 1;
	return;
}

static void *a_thread_func()
{
	struct sigaction act;
	act.sa_flags = 0;
	act.sa_handler = handler;
	sigemptyset(&act.sa_mask);
	sigaction(SIGTOTEST, &act, 0);

	sem1 = INMAIN;

	while (sem1 == INMAIN)
		sleep(1);

	sleep(5);

	handler_called = -1;
	pthread_exit(0);
	return NULL;
}

int main(void)
{
	pthread_t new_th;

	sem1 = INTHREAD;

	if (pthread_create(&new_th, NULL, a_thread_func, NULL) != 0) {
		perror("Error creating thread\n");
		return PTS_UNRESOLVED;
	}

	while (sem1 == INTHREAD)
		sleep(1);

	if (pthread_kill(new_th, SIGTOTEST) != 0) {
		printf("Test FAILED: Couldn't send signal to thread\n");
		return PTS_FAIL;
	}

	sem1 = INTHREAD;

	while (handler_called == 0)
		sleep(1);

	if (handler_called == -1) {
		printf("Test FAILED: Kill request timed out\n");
		return PTS_FAIL;
	} else if (handler_called == 0) {
		printf("Test FAILED: Thread did not received or handle\n");
		return PTS_FAIL;
	}

	printf("Test PASSED\n");
	return PTS_PASS;
}
