* Added some pthread_attr_destroy() and pthread_create() tests from
posixtestsuite into our repository. * A few of the latter ones actually fail on Haiku. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33776 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,17 +1,19 @@
|
||||
SubDir HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces ;
|
||||
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces difftime ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces fork ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces kill ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces pthread_key_create ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces pthread_key_delete ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces pthread_getspecific ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces pthread_once ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces pthread_setspecific ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces sighold ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces sigignore ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces sigprocmask ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces sigrelse ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces signal ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces sigset ;
|
||||
SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces sigsuspend ;
|
||||
HaikuSubInclude difftime ;
|
||||
HaikuSubInclude fork ;
|
||||
HaikuSubInclude kill ;
|
||||
HaikuSubInclude pthread_attr_destroy ;
|
||||
HaikuSubInclude pthread_create ;
|
||||
HaikuSubInclude pthread_key_create ;
|
||||
HaikuSubInclude pthread_key_delete ;
|
||||
HaikuSubInclude pthread_getspecific ;
|
||||
HaikuSubInclude pthread_once ;
|
||||
HaikuSubInclude pthread_setspecific ;
|
||||
HaikuSubInclude sighold ;
|
||||
HaikuSubInclude sigignore ;
|
||||
HaikuSubInclude sigprocmask ;
|
||||
HaikuSubInclude sigrelse ;
|
||||
HaikuSubInclude signal ;
|
||||
HaikuSubInclude sigset ;
|
||||
HaikuSubInclude sigsuspend ;
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
|
||||
* Test that pthread_attr_destroy()
|
||||
* shall destory a thread attributes object. An implementation may cause
|
||||
* pthread_attr_destroy() to set 'attr' to an implementation-defined invalid
|
||||
* value.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Initialize a pthread_attr_t object using pthread_attr_init()
|
||||
* 2. Destroy that initialized attribute using pthread_attr_destroy()
|
||||
* 3. Using pthread_attr_create(), pass to it the destroyed attribute. It
|
||||
* should return the error EINVAL, the value specified by 'attr' is
|
||||
* is invalid.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
|
||||
void *a_thread_func()
|
||||
{
|
||||
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t new_th;
|
||||
pthread_attr_t new_attr;
|
||||
int ret;
|
||||
|
||||
/* Initialize attribute */
|
||||
if(pthread_attr_init(&new_attr) != 0)
|
||||
{
|
||||
perror("Cannot initialize attribute object\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Destroy attribute */
|
||||
if(pthread_attr_destroy(&new_attr) != 0)
|
||||
{
|
||||
perror("Cannot destroy the attribute object\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Creating a thread, passing to it the destroyed attribute, should
|
||||
* result in an error value of EINVAL (invalid 'attr' value). */
|
||||
ret=pthread_create(&new_th, &new_attr, a_thread_func, NULL);
|
||||
|
||||
if(ret==EINVAL)
|
||||
{
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
else if((ret != 0) && ((ret == EPERM) || (ret == EAGAIN)))
|
||||
{
|
||||
perror("Error created a new thread\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
else if(ret==0)
|
||||
{
|
||||
printf("Test PASSED: NOTE*: Though returned 0 when creating a thread with a destroyed attribute, this behavior is compliant with garbage-in-garbage-out. \n");
|
||||
return PTS_PASS;
|
||||
} else
|
||||
{
|
||||
printf("Test FAILED: (1) Incorrect return code from pthread_create(); %d not EINVAL or (2) Error in pthread_create()'s behavior in returning error codes \n", ret);
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
|
||||
* A destroyed 'attr' attributes object can be reinitialized using
|
||||
* pthread_attr_init(); the results of otherwise referencing the object
|
||||
* after it has been destroyed are undefined.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Initialize a pthread_attr_t object using pthread_attr_init()
|
||||
* 2. Destroy that initialized attribute using pthread_attr_destroy()
|
||||
* 3. Initialize the pthread_attr_t object again. This should not result
|
||||
* in an error.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_attr_t new_attr;
|
||||
|
||||
/* Initialize attribute */
|
||||
if(pthread_attr_init(&new_attr) != 0)
|
||||
{
|
||||
perror("Cannot initialize attribute object\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Destroy attribute */
|
||||
if(pthread_attr_destroy(&new_attr) != 0)
|
||||
{
|
||||
perror("Cannot destroy the attribute object\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Initialize attribute. This shouldn't result in an error. */
|
||||
if(pthread_attr_init(&new_attr) != 0)
|
||||
{
|
||||
printf("Test FAILED\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
|
||||
* Upon successful completion, pthread_attr_destroy() shall return a value of 0.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Initialize a pthread_attr_t object using pthread_attr_init()
|
||||
* 2. Destroy that initialized attribute using pthread_attr_destroy().
|
||||
* This should return 0;
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_attr_t new_attr;
|
||||
|
||||
/* Initialize attribute */
|
||||
if(pthread_attr_init(&new_attr) != 0)
|
||||
{
|
||||
perror("Cannot initialize attribute object\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Destroy attribute */
|
||||
if(pthread_attr_destroy(&new_attr) != 0)
|
||||
{
|
||||
printf("Test FAILED\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
SubDir HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces pthread_attr_destroy ;
|
||||
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) $(DOTDOT) include ] ;
|
||||
|
||||
SimpleTest pthread_attr_destroy_1-1 : 1-1.c ;
|
||||
SimpleTest pthread_attr_destroy_2-1 : 2-1.c ;
|
||||
SimpleTest pthread_attr_destroy_3-1 : 3-1.c ;
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
|
||||
* Test that pthread_create() creates a new thread with attributes specified
|
||||
* by 'attr', within a process.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Create a thread using pthread_create()
|
||||
* 2. Compare the thread ID of 'main' to the thread ID of the newly created
|
||||
* thread. They should be different.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
void *a_thread_func()
|
||||
{
|
||||
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t main_th, new_th;
|
||||
|
||||
if(pthread_create(&new_th, NULL, a_thread_func, NULL) != 0)
|
||||
{
|
||||
perror("Error creating thread\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Obtain the thread ID of this main function */
|
||||
main_th=pthread_self();
|
||||
|
||||
/* Compare the thread ID of the new thread to the main thread.
|
||||
* They should be different. If not, the test fails. */
|
||||
if(pthread_equal(new_th, main_th) != 0)
|
||||
{
|
||||
printf("Test FAILED: A new thread wasn't created\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
|
||||
* Test that pthread_create() creates a new thread with attributes specified
|
||||
* by 'attr', within a process.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Create a thread using pthread_create()
|
||||
* 2. Cancel that thread with pthread_cancel()
|
||||
* 3. If that thread doesn't exist, then it pthread_cancel() will return
|
||||
* an error code. This would mean that pthread_create() did not create
|
||||
* a thread successfully.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
void *a_thread_func()
|
||||
{
|
||||
sleep(10);
|
||||
|
||||
/* Shouldn't reach here. If we do, then the pthread_cancel()
|
||||
* function did not succeed. */
|
||||
perror("Could not send cancel request correctly\n");
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t new_th;
|
||||
|
||||
if(pthread_create(&new_th, NULL, a_thread_func, NULL) < 0)
|
||||
{
|
||||
perror("Error creating thread\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Try to cancel the newly created thread. If an error is returned,
|
||||
* then the thread wasn't created successfully. */
|
||||
if(pthread_cancel(new_th) != 0)
|
||||
{
|
||||
printf("Test FAILED: A new thread wasn't created\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
|
||||
* Test that pthread_create() creates a new thread with attributes specified
|
||||
* by 'attr', within a process.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Create a new thread that will go into a never-ending while loop.
|
||||
* 2. If the thread is truly asynchronise, then the main function will
|
||||
* continue instead of waiting for the thread to return (which in never
|
||||
* does in this test case).
|
||||
* 3. An alarm is set to go off (i.e. send the SIGARLM signal) after 3
|
||||
* seconds. This is done for 'timeing-out' reasons, in case main DOES
|
||||
* wait for the thread to return. This would also mean that the test
|
||||
* failed.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
void *a_thread_function();
|
||||
void alarm_handler();
|
||||
|
||||
pthread_t a;
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
/* Set the action for SIGALRM to generate an error if it is
|
||||
* reached. This is because if SIGALRM was sent, then the
|
||||
* test timed out. */
|
||||
if (signal(SIGALRM, alarm_handler) == SIG_ERR)
|
||||
{
|
||||
printf("Error in signal()\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* SIGALRM will be sent in 5 seconds. */
|
||||
alarm(5);
|
||||
|
||||
/* Create a new thread. */
|
||||
if(pthread_create(&a, NULL, a_thread_function, NULL) != 0)
|
||||
{
|
||||
perror("Error creating thread\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
pthread_cancel(a);
|
||||
/* If 'main' has reached here, then the test passed because it means
|
||||
* that the thread is truly asynchronise, and main isn't waiting for
|
||||
* it to return in order to move on. */
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
|
||||
/* A never-ending thread function */
|
||||
void *a_thread_function()
|
||||
{
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
|
||||
while(1)
|
||||
sleep(1);
|
||||
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If this handler is called, that means that the test has failed. */
|
||||
void alarm_handler()
|
||||
{
|
||||
printf("Test FAILED\n");
|
||||
exit(PTS_FAIL);
|
||||
}
|
||||
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Bull S.A.. All rights reserved.
|
||||
* Created by: Sebastien Decugis
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it would be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
|
||||
|
||||
* This sample test aims to check the following assertion:
|
||||
*
|
||||
* pthread_create creates a new thread within the process
|
||||
|
||||
* The steps are:
|
||||
*
|
||||
* -> get the thread ID and the process ID of the main thread.
|
||||
* -> create a new thread, get the thread & process ID.
|
||||
* -> check that the thread IDs are different but process IDs are the same
|
||||
|
||||
* The test fails if the thread IDs are the same or the proces IDs are different.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
/* Some routines are part of the XSI Extensions */
|
||||
#ifndef WITHOUT_XOPEN
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
/********************************************************************************************/
|
||||
/****************************** standard includes *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sched.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
/********************************************************************************************/
|
||||
/****************************** Test framework *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include "testfrmw.h"
|
||||
#include "testfrmw.c"
|
||||
/* This header is responsible for defining the following macros:
|
||||
* UNRESOLVED(ret, descr);
|
||||
* where descr is a description of the error and ret is an int (error code for example)
|
||||
* FAILED(descr);
|
||||
* where descr is a short text saying why the test has failed.
|
||||
* PASSED();
|
||||
* No parameter.
|
||||
*
|
||||
* Both three macros shall terminate the calling process.
|
||||
* The testcase shall not terminate in any other maneer.
|
||||
*
|
||||
* The other file defines the functions
|
||||
* void output_init()
|
||||
* void output(char * string, ...)
|
||||
*
|
||||
* Those may be used to output information.
|
||||
*/
|
||||
|
||||
/********************************************************************************************/
|
||||
/********************************** Configuration ******************************************/
|
||||
/********************************************************************************************/
|
||||
#ifndef VERBOSE
|
||||
#define VERBOSE 1
|
||||
#endif
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Test cases *****************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
#include "threads_scenarii.c"
|
||||
|
||||
/* This file will define the following objects:
|
||||
* scenarii: array of struct __scenario type.
|
||||
* NSCENAR : macro giving the total # of scenarii
|
||||
* scenar_init(): function to call before use the scenarii array.
|
||||
* scenar_fini(): function to call after end of use of the scenarii array.
|
||||
*/
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Real Test *****************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
struct testdata
|
||||
{
|
||||
pthread_t tid;
|
||||
pid_t pid;
|
||||
sem_t * sem;
|
||||
};
|
||||
|
||||
int global; /* This value is used to check both threads share the same process memory (and not a copy) */
|
||||
|
||||
void * threaded (void * arg)
|
||||
{
|
||||
struct testdata * td=(struct testdata *) arg;
|
||||
pthread_t mytid;
|
||||
pid_t mypid;
|
||||
int ret = 0;
|
||||
|
||||
/* Compare the process IDs */
|
||||
mypid=getpid();
|
||||
#if VERBOSE > 0
|
||||
output(" Main pid: %i thread pid: %i\n", td->pid, mypid);
|
||||
#endif
|
||||
|
||||
if (mypid != td->pid)
|
||||
{
|
||||
FAILED("New thread does not belong to the same process as its parent thread");
|
||||
}
|
||||
|
||||
/* Compare the threads IDs */
|
||||
mytid = pthread_self();
|
||||
#if VERBOSE > 0
|
||||
/* pthread_t is a pointer with Linux/nptl. This output can be erroneous for other arcs */
|
||||
output(" Main tid: %p thread tid: %p\n", td->tid, mytid);
|
||||
#endif
|
||||
|
||||
if (pthread_equal(mytid, td->tid) != 0)
|
||||
{
|
||||
FAILED("The created thread has the same thread ID as its parent");
|
||||
}
|
||||
|
||||
/* Change the global value */
|
||||
global++;
|
||||
|
||||
/* Post the semaphore to unlock the main thread in case of a detached thread */
|
||||
do { ret = sem_post(td->sem); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); }
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int ret=0;
|
||||
struct testdata td;
|
||||
void * rval;
|
||||
pthread_t child;
|
||||
int i;
|
||||
|
||||
output_init();
|
||||
|
||||
td.tid=pthread_self();
|
||||
td.pid=getpid();
|
||||
|
||||
scenar_init();
|
||||
|
||||
for (i=0; i < NSCENAR; i++)
|
||||
{
|
||||
#if VERBOSE > 0
|
||||
output("-----\n");
|
||||
output("Starting test with scenario (%i): %s\n", i, scenarii[i].descr);
|
||||
#endif
|
||||
|
||||
td.sem = &scenarii[i].sem;
|
||||
|
||||
global = 2*i;
|
||||
|
||||
ret = pthread_create(&child, &scenarii[i].ta, threaded, &td);
|
||||
switch (scenarii[i].result)
|
||||
{
|
||||
case 0: /* Operation was expected to succeed */
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to create this thread"); }
|
||||
break;
|
||||
|
||||
case 1: /* Operation was expected to fail */
|
||||
if (ret == 0) { UNRESOLVED(-1, "An error was expected but the thread creation succeeded"); }
|
||||
break;
|
||||
|
||||
case 2: /* We did not know the expected result */
|
||||
default:
|
||||
#if VERBOSE > 0
|
||||
if (ret == 0)
|
||||
{ output("Thread has been created successfully for this scenario\n"); }
|
||||
else
|
||||
{ output("Thread creation failed with the error: %s\n", strerror(ret)); }
|
||||
#endif
|
||||
}
|
||||
if (ret == 0) /* The new thread is running */
|
||||
{
|
||||
if (scenarii[i].detached == 0)
|
||||
{
|
||||
ret = pthread_join(child, &rval);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to join a thread"); }
|
||||
|
||||
if (rval != &td)
|
||||
{
|
||||
FAILED("Could not get the thread return value. Did it execute?");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just wait for the thread terminate */
|
||||
do { ret = sem_wait(td.sem); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); }
|
||||
}
|
||||
|
||||
if (global != (2*i + 1))
|
||||
{
|
||||
/* Maybe a possible issue with CPU memory-caching here? */
|
||||
FAILED("The threads do not share the same process memory.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scenar_fini();
|
||||
#if VERBOSE > 0
|
||||
output("-----\n");
|
||||
output("All test data destroyed\n");
|
||||
output("Test PASSED\n");
|
||||
#endif
|
||||
|
||||
PASSED;
|
||||
}
|
||||
|
||||
+263
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Bull S.A.. All rights reserved.
|
||||
* Created by: Sebastien Decugis
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it would be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
|
||||
|
||||
* This sample test aims to check the following assertion:
|
||||
*
|
||||
* pthread_create creates a thread with attributes as specified in the attr parameter.
|
||||
|
||||
* The steps are:
|
||||
*
|
||||
* -> Create a new thread with known parameters.
|
||||
* -> Check the thread behavior conforms to these parameters.
|
||||
* This checking consists in:
|
||||
* -> If an alternative stack has been specified, check that the new thread stack is within this specified area.
|
||||
* -> If stack size and guard size are known, check that accessing the guard size fails. (new process)
|
||||
* -> If we are able to run threads with high priority and known sched policy, check that a high priority thread executes before a low priority thread.
|
||||
(This will be done in another test has it fails with Linux kernel (2.6.8 at least)
|
||||
* -> The previous test could be extended to cross-process threads to check the scope attribute behavior (postponned for now).
|
||||
* (*) The detachstate attribute is not tested cause this would mean a speculative test. Moreover, it is already tested elsewhere.
|
||||
|
||||
* The test fails if one of those tests fails.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
/* Some routines are part of the XSI Extensions */
|
||||
#ifndef WITHOUT_XOPEN
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
/********************************************************************************************/
|
||||
/****************************** standard includes *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sched.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
/********************************************************************************************/
|
||||
/****************************** Test framework *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include "testfrmw.h"
|
||||
#include "testfrmw.c"
|
||||
/* This header is responsible for defining the following macros:
|
||||
* UNRESOLVED(ret, descr);
|
||||
* where descr is a description of the error and ret is an int (error code for example)
|
||||
* FAILED(descr);
|
||||
* where descr is a short text saying why the test has failed.
|
||||
* PASSED();
|
||||
* No parameter.
|
||||
*
|
||||
* Both three macros shall terminate the calling process.
|
||||
* The testcase shall not terminate in any other maneer.
|
||||
*
|
||||
* The other file defines the functions
|
||||
* void output_init()
|
||||
* void output(char * string, ...)
|
||||
*
|
||||
* Those may be used to output information.
|
||||
*/
|
||||
|
||||
/********************************************************************************************/
|
||||
/********************************** Configuration ******************************************/
|
||||
/********************************************************************************************/
|
||||
#ifndef VERBOSE
|
||||
#define VERBOSE 1
|
||||
#endif
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Test cases *****************************************/
|
||||
/********************************************************************************************/
|
||||
#define STD_MAIN /* This allows main() to be defined in the included file */
|
||||
#include "threads_scenarii.c"
|
||||
|
||||
/* This file will define the following objects:
|
||||
* scenarii: array of struct __scenario type.
|
||||
* NSCENAR : macro giving the total # of scenarii
|
||||
* scenar_init(): function to call before use the scenarii array.
|
||||
* scenar_fini(): function to call after end of use of the scenarii array.
|
||||
*/
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Real Test *****************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
/* The overflow function is used to test the stack overflow */
|
||||
void * overflow(void * arg)
|
||||
{
|
||||
void * current;
|
||||
void * pad[50]; /* We want to consume the stack quickly */
|
||||
long stacksize = sysconf(_SC_THREAD_STACK_MIN); /* make sure we touch the current stack memory */
|
||||
int ret=0;
|
||||
|
||||
pad[1]=NULL; /* so compiler stops complaining about unused variables */
|
||||
|
||||
if (arg == NULL)
|
||||
{
|
||||
/* first call */
|
||||
current = overflow(¤t);
|
||||
|
||||
/* Terminate the overflow thread */
|
||||
/* Post the semaphore to unlock the main thread in case of a detached thread */
|
||||
do { ret = sem_post(&scenarii[sc].sem); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); }
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* we cast the pointers into long, which might be a problem on some architectures... */
|
||||
if ( ((long)arg) < ((long)¤t))
|
||||
{
|
||||
/* the stack is growing up */
|
||||
if ( ((long)¤t) - ((long)arg) >= stacksize)
|
||||
{
|
||||
output("Growing up stack started below %p and we are currently up to %p\n", arg, ¤t);
|
||||
return (void *)0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the stack is growing down */
|
||||
if ( ((long)arg) - ((long)¤t) >= stacksize)
|
||||
{
|
||||
output("Growing down stack started upon %p and we are currently down to %p\n", arg, ¤t);
|
||||
return (void *)0;
|
||||
}
|
||||
}
|
||||
|
||||
/* We are not yet overflowing, so we loop */
|
||||
{
|
||||
return overflow(arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void * threaded (void * arg)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#if VERBOSE > 4
|
||||
output("Thread %i starting...\n", sc);
|
||||
#endif
|
||||
|
||||
/* Alternate stack test */
|
||||
if (scenarii[sc].bottom != NULL)
|
||||
{
|
||||
#ifdef WITHOUT_XOPEN
|
||||
output("Unable to test the alternate stack feature; need an integer pointer cast\n");
|
||||
#else
|
||||
intptr_t stack_start, stack_end, current_pos;
|
||||
|
||||
stack_start = (intptr_t) scenarii[sc].bottom;
|
||||
stack_end = stack_start + (intptr_t)sysconf(_SC_THREAD_STACK_MIN);
|
||||
current_pos = (intptr_t)&ret;
|
||||
|
||||
#if VERBOSE > 2
|
||||
output("Stack bottom: %p\n", scenarii[sc].bottom);
|
||||
output("Stack end : %p (stack is 0x%lx bytes)\n", (void *)stack_end, stack_end - stack_start);
|
||||
output("Current pos : %p\n", &ret);
|
||||
#endif
|
||||
if ((stack_start > current_pos) || (current_pos > stack_end))
|
||||
{ FAILED("The specified stack was not used.\n"); }
|
||||
|
||||
#endif // WITHOUT_XOPEN
|
||||
}
|
||||
|
||||
|
||||
/* Guard size test */
|
||||
if ((scenarii[sc].bottom == NULL) /* no alternative stack was specified */
|
||||
&& (scenarii[sc].guard == 2) /* guard area size is 1 memory page */
|
||||
&& (scenarii[sc].altsize == 1))/* We know the stack size */
|
||||
{
|
||||
pid_t child, ctrl;
|
||||
int status;
|
||||
|
||||
child=fork(); /* We'll test the feature in another process as this test may segfault */
|
||||
|
||||
if (child == -1) { UNRESOLVED(errno, "Failed to fork()"); }
|
||||
|
||||
if (child != 0) /* father */
|
||||
{
|
||||
/* Just wait for the child and check its return value */
|
||||
ctrl = waitpid(child, &status, 0);
|
||||
if (ctrl != child) { UNRESOLVED(errno, "Failed to wait for process termination"); }
|
||||
|
||||
if (WIFEXITED(status)) /* The process exited */
|
||||
{
|
||||
if (WEXITSTATUS(status) == 0)
|
||||
{ FAILED("Overflow into the guard area did not fail"); }
|
||||
if (WEXITSTATUS(status) == PTS_UNRESOLVED)
|
||||
{ UNRESOLVED(-1, "The child process returned unresolved status"); }
|
||||
#if VERBOSE > 4
|
||||
else
|
||||
{ output("The child process returned: %i\n", WEXITSTATUS(status)); }
|
||||
}
|
||||
else
|
||||
{
|
||||
output("The child process did not returned\n");
|
||||
if (WIFSIGNALED(status))
|
||||
output("It was killed with signal %i\n", WTERMSIG(status));
|
||||
else
|
||||
output("neither was it killed. (status = %i)\n", status);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (child == 0) /* this is the new process */
|
||||
{
|
||||
pthread_t th;
|
||||
|
||||
ret = pthread_create(&th, &scenarii[sc].ta, overflow, NULL); /* Create a new thread with the same attributes */
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to create another thread with the same attributes in the new process"); }
|
||||
|
||||
if (scenarii[sc].detached == 0)
|
||||
{
|
||||
ret = pthread_join(th, NULL);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to join a thread"); }
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just wait for the thread to terminate */
|
||||
do { ret = sem_wait(&scenarii[sc].sem); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); }
|
||||
}
|
||||
|
||||
/* Terminate the child process here */
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Post the semaphore to unlock the main thread in case of a detached thread */
|
||||
do { ret = sem_post(&scenarii[sc].sem); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); }
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Bull S.A.. All rights reserved.
|
||||
* Created by: Sebastien Decugis
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it would be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
|
||||
|
||||
* This sample test aims to check the following assertion:
|
||||
*
|
||||
* pthread_create creates a thread with attributes as specified in the attr parameter.
|
||||
|
||||
* The steps are:
|
||||
*
|
||||
* -> See test 1-5.c for details
|
||||
* -> This one will test the scheduling behavior is correct.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
/* Some routines are part of the XSI Extensions */
|
||||
#ifndef WITHOUT_XOPEN
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
/********************************************************************************************/
|
||||
/****************************** standard includes *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sched.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
/********************************************************************************************/
|
||||
/****************************** Test framework *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include "testfrmw.h"
|
||||
#include "testfrmw.c"
|
||||
/* This header is responsible for defining the following macros:
|
||||
* UNRESOLVED(ret, descr);
|
||||
* where descr is a description of the error and ret is an int (error code for example)
|
||||
* FAILED(descr);
|
||||
* where descr is a short text saying why the test has failed.
|
||||
* PASSED();
|
||||
* No parameter.
|
||||
*
|
||||
* Both three macros shall terminate the calling process.
|
||||
* The testcase shall not terminate in any other maneer.
|
||||
*
|
||||
* The other file defines the functions
|
||||
* void output_init()
|
||||
* void output(char * string, ...)
|
||||
*
|
||||
* Those may be used to output information.
|
||||
*/
|
||||
|
||||
/********************************************************************************************/
|
||||
/********************************** Configuration ******************************************/
|
||||
/********************************************************************************************/
|
||||
#ifndef VERBOSE
|
||||
#define VERBOSE 1
|
||||
#endif
|
||||
|
||||
/* The value below shall be >= to the # of CPU on the test architecture */
|
||||
#define NCPU (4)
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Test cases *****************************************/
|
||||
/********************************************************************************************/
|
||||
#define STD_MAIN /* This allows main() to be defined in the included file */
|
||||
|
||||
#include "threads_scenarii.c"
|
||||
|
||||
/* This file will define the following objects:
|
||||
* scenarii: array of struct __scenario type.
|
||||
* NSCENAR : macro giving the total # of scenarii
|
||||
* scenar_init(): function to call before use the scenarii array.
|
||||
* scenar_fini(): function to call after end of use of the scenarii array.
|
||||
*/
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Real Test *****************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
|
||||
/* The 2 following functions are used for the scheduling tests */
|
||||
void * lp_func(void * arg)
|
||||
{
|
||||
int * ctrl = (int *) arg;
|
||||
*ctrl=2;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void * hp_func(void * arg)
|
||||
{
|
||||
int *ctrl = (int *) arg;
|
||||
int dummy=0, i;
|
||||
do
|
||||
{
|
||||
/* some dummy task */
|
||||
dummy += 3;
|
||||
dummy %= 17;
|
||||
dummy *= 47;
|
||||
for (i=0; i<1000000000; i++);
|
||||
#if VERBOSE > 6
|
||||
output("%p\n", pthread_self());
|
||||
#endif
|
||||
}
|
||||
while (*ctrl == 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void * threaded (void * arg)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#if VERBOSE > 4
|
||||
output("Thread %i starting...\n", sc);
|
||||
#endif
|
||||
|
||||
/* Scheduling (priority) tests */
|
||||
if ((sysconf(_SC_THREAD_PRIORITY_SCHEDULING) > 0)
|
||||
&& (scenarii[sc].explicitsched != 0)
|
||||
&& (scenarii[sc].schedpolicy != 0)
|
||||
&& (scenarii[sc].schedparam == 1))
|
||||
{
|
||||
/* We will create NCPU threads running with a high priority with the same sched policy policy
|
||||
and one with a low-priority.
|
||||
The low-priority thread should not run until the other threads stop running,
|
||||
unless the machine has more than NCPU processors... */
|
||||
|
||||
pthread_t hpth[NCPU]; /* High priority threads */
|
||||
pthread_t lpth; /* Low Priority thread */
|
||||
int ctrl; /* Check value */
|
||||
pthread_attr_t ta;
|
||||
struct sched_param sp;
|
||||
int policy;
|
||||
int i=0;
|
||||
struct timespec now, timeout;
|
||||
|
||||
/* Start with checking we are executing with the required parameters */
|
||||
ret = pthread_getschedparam(pthread_self(), &policy, &sp);
|
||||
if (ret != 0) { UNRESOLVED(ret , "Failed to get current thread policy"); }
|
||||
|
||||
if (((scenarii[sc].schedpolicy == 1) && (policy != SCHED_FIFO))
|
||||
|| ((scenarii[sc].schedpolicy == 2) && (policy != SCHED_RR)))
|
||||
{
|
||||
FAILED("The thread is not using the scheduling policy that was required");
|
||||
}
|
||||
if (((scenarii[sc].schedparam == 1) && (sp.sched_priority != sched_get_priority_max(policy)))
|
||||
|| ((scenarii[sc].schedparam ==-1) && (sp.sched_priority != sched_get_priority_min(policy))))
|
||||
{
|
||||
|
||||
FAILED("The thread is not using the scheduling parameter that was required");
|
||||
}
|
||||
|
||||
ctrl = 0; /* Initial state */
|
||||
|
||||
/* Get the policy information */
|
||||
ret = pthread_attr_getschedpolicy(&scenarii[sc].ta, &policy);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to read sched policy"); }
|
||||
|
||||
/* We put a timeout cause the test might lock the machine when it runs */
|
||||
alarm(60);
|
||||
|
||||
/* Create the high priority threads */
|
||||
ret = pthread_attr_init(&ta);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to initialize a thread attribute object"); }
|
||||
|
||||
ret = pthread_attr_setinheritsched(&ta, PTHREAD_EXPLICIT_SCHED);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to set inheritsched attribute"); }
|
||||
|
||||
ret = pthread_attr_setschedpolicy(&ta, policy);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to set the sched policy"); }
|
||||
|
||||
sp.sched_priority = sched_get_priority_max(policy) - 1;
|
||||
|
||||
ret = pthread_attr_setschedparam(&ta, &sp);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to set the sched param"); }
|
||||
|
||||
#if VERBOSE > 1
|
||||
output("Starting %i high- and 1 low-priority threads.\n", NCPU);
|
||||
#endif
|
||||
for (i=0; i<NCPU; i++)
|
||||
{
|
||||
ret = pthread_create(&hpth[i], &ta, hp_func, &ctrl);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to create enough threads"); }
|
||||
}
|
||||
#if VERBOSE > 5
|
||||
output("The %i high-priority threads are running\n", NCPU);
|
||||
#endif
|
||||
|
||||
/* Create the low-priority thread */
|
||||
sp.sched_priority = sched_get_priority_min(policy);
|
||||
|
||||
ret = pthread_attr_setschedparam(&ta, &sp);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to set the sched param"); }
|
||||
|
||||
ret = pthread_create(&lpth, &ta, lp_func, &ctrl);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to create enough threads"); }
|
||||
|
||||
/* Keep going */
|
||||
ret = clock_gettime(CLOCK_REALTIME, &now);
|
||||
if (ret != 0) { UNRESOLVED(errno, "Failed to read current time"); }
|
||||
|
||||
timeout.tv_sec = now.tv_sec;
|
||||
timeout.tv_nsec = now.tv_nsec + 500000000;
|
||||
while (timeout.tv_nsec >= 1000000000)
|
||||
{
|
||||
timeout.tv_sec++;
|
||||
timeout.tv_nsec -= 1000000000;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (ctrl != 0)
|
||||
{
|
||||
output("The low priority thread executed. This might be normal if you have more than %i CPU.\n", NCPU + 1);
|
||||
FAILED("Low priority thread executed -- the sched parameters are ignored?");
|
||||
}
|
||||
ret = clock_gettime(CLOCK_REALTIME, &now);
|
||||
if (ret != 0) { UNRESOLVED(errno, "Failed to read current time"); }
|
||||
#if VERBOSE > 5
|
||||
output("Time: %d.%09d (to: %d.%09d)\n", now.tv_sec, now.tv_nsec, timeout.tv_sec, timeout.tv_nsec);
|
||||
#endif
|
||||
}
|
||||
while ((now.tv_sec <= timeout.tv_sec) && (now.tv_nsec <= timeout.tv_nsec));
|
||||
|
||||
/* Ok the low priority thread did not execute :) */
|
||||
|
||||
/* tell the other high priority to terminate */
|
||||
ctrl = 1;
|
||||
|
||||
for (i=0; i<NCPU; i++)
|
||||
{
|
||||
ret = pthread_join(hpth[i], NULL);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to join a thread"); }
|
||||
}
|
||||
|
||||
/* Ok so now the low priority should execute when we stop this one (or earlier). */
|
||||
ret = pthread_join(lpth, NULL);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to join the low priority thread"); }
|
||||
|
||||
/* We just check that it executed */
|
||||
if (ctrl != 2) { FAILED("Joined the low-priority thread but it did not execute."); }
|
||||
|
||||
#if VERBOSE > 1
|
||||
output("The scheduling parameter was set accordingly to the thread attribute.\n");
|
||||
#endif
|
||||
|
||||
/* We're done. */
|
||||
ret = pthread_attr_destroy(&ta);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to destroy a thread attribute object"); }
|
||||
}
|
||||
|
||||
/* Post the semaphore to unlock the main thread in case of a detached thread */
|
||||
do { ret = sem_post(&scenarii[sc].sem); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); }
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
|
||||
* Test pthread_create().
|
||||
*
|
||||
* If pthread_create() fails, no new thread is created and the contents of the
|
||||
* location referenced by 'thread' is undefined.
|
||||
*
|
||||
* EXPLANATION: 3 ways that pthread_create can fail is if (1) The system lacked memory
|
||||
* resources. (2) The caller did not have the appropriate permissions. (3) An invalid
|
||||
* attributes object was passed. Since the last situation is the easiest to implement, that
|
||||
* is the one I chose to use in order to make pthread_create fail.
|
||||
*
|
||||
* The problem with that is that accessing an uninitialized attributes object will cause a
|
||||
* segmentation fault (since it usually points to garbage). So the idea here is to catch
|
||||
* the SIGSEGV signal (segmentation faults), and to see if the thread was ever created, by
|
||||
* setting a flag in the thread's starting routine.
|
||||
*
|
||||
* I recognize that causing pthread_create() to fail gracefully is a very difficult task,
|
||||
* especially taking into consideration that a lot of it is implementation-specific. I did
|
||||
* try to manually set the members of a pthread_attr_t object to invalid values, but that didn't
|
||||
* seem to make pthread_create() fail at all, in any of the implementations I tested on. So for
|
||||
* now, this is what we have.
|
||||
*
|
||||
*
|
||||
* Steps:
|
||||
* 1. Create a thread using pthread_create() with an invalid attributes object (uninitialized).
|
||||
* 2. Catch the SIGSEGV (seg fault) signal. In the signal handler, check to make sure that
|
||||
* the start routine for the thread was never reached, meaning the thread was never created.
|
||||
* 3. If SIGSEGV was not caught in 10 seconds, the test times out and fails. If the signal
|
||||
* was caught, but the thread start routine was called at some point, the test also fails.
|
||||
*
|
||||
*
|
||||
* - [email protected]: 2004-04-30
|
||||
* This case will end with segmentation fault.
|
||||
* I happened to find on NPTL pthread_create() can fail is
|
||||
* pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_INHERIT), while
|
||||
* does not call pthread_attr_setschedparam() to set the prority. (since
|
||||
* by default the priority will be 0. But this is implementation specific.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
int created_thread; /* Flag indicating that the thread start routine was reached, and
|
||||
therefore, the thread was created. */
|
||||
int segfault_flag; /* Flag indicating that a segmentation fault occured. */
|
||||
|
||||
/* Thread's start routine. */
|
||||
void *a_thread_func()
|
||||
{
|
||||
/* Indicate that the thread start routine was reached. If it was reached, the test
|
||||
* fails, as the thread should have not been created in the first place. */
|
||||
created_thread = 1;
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Signal handler for SIGSEGV (segmentation fault signal) */
|
||||
void sig_handler(int sig)
|
||||
{
|
||||
/* If a segmentation fault occured when it was supposed to (i.e. when pthread_create()
|
||||
* was called with the invalid attributes object). */
|
||||
if(segfault_flag == 1)
|
||||
{
|
||||
/* check if the thread start routine was called. If yes, then the thread was
|
||||
* created, meaning the test fails. */
|
||||
if(created_thread == 1)
|
||||
{
|
||||
printf("Test FAILED: Created thread though an invalid attribute was passed to pthread_create().\n");
|
||||
pthread_exit((void*)PTS_FAIL);
|
||||
}
|
||||
|
||||
printf("Test PASSED\n");
|
||||
pthread_exit((void*)PTS_PASS);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Test FAILED: Did not receive segmentation fault signal, waited 10 seconds.\n");
|
||||
pthread_exit((void*)PTS_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* MAIN */
|
||||
int main()
|
||||
{
|
||||
pthread_t new_th;
|
||||
pthread_attr_t inv_attr;
|
||||
struct sigaction act;
|
||||
|
||||
/* Inializing flags. */
|
||||
segfault_flag = 1;
|
||||
created_thread = 0;
|
||||
|
||||
/* Set signal handler for SIGSEGV (seg fault) */
|
||||
act.sa_handler = sig_handler;
|
||||
act.sa_flags = 0;
|
||||
sigaction(SIGSEGV, &act, NULL);
|
||||
|
||||
/* Create the thread with the invalid, uninitialized attributes object. */
|
||||
pthread_create(&new_th, &inv_attr, a_thread_func, NULL);
|
||||
|
||||
/* Should not reach here if process correctly seg-faulted. */
|
||||
segfault_flag = 0;
|
||||
|
||||
/* Timeout after 10 seconds if a segfault was not encountered. The test then fails. */
|
||||
sleep(10);
|
||||
|
||||
/* Manually send the SIGSEGV signal to the signal handler. If this point is reached,
|
||||
* the test fails. */
|
||||
if(raise(SIGSEGV) != 0)
|
||||
{
|
||||
perror("Error in raise()\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
printf("Test FAILED.\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Intel Corporation. All rights reserved.
|
||||
* 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.
|
||||
*
|
||||
* [email protected]
|
||||
*
|
||||
* if _POSIX_THREAD_CPUTIME is defined, the new thread shall have a CPU-time
|
||||
* clock accessible, and the initial value of this clock shall be set to 0.
|
||||
*/
|
||||
/* Create a new thread and get the time of the thread CUP-time clock
|
||||
* using clock_gettime().
|
||||
* Note, the tv_nsec cannot be exactly 0 at the time of calling
|
||||
* clock_gettime() since the thread has executed some time. */
|
||||
|
||||
#define _XOPEN_SOURCE 600
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
void *a_thread_func()
|
||||
{
|
||||
clockid_t cpuclock;
|
||||
struct timespec ts = {.tv_sec = 1, .tv_nsec = 1};
|
||||
pthread_getcpuclockid(pthread_self(), &cpuclock);
|
||||
clock_gettime(cpuclock, &ts);
|
||||
/* Just test the tv_sec field here. */
|
||||
if (ts.tv_sec != 0)
|
||||
{
|
||||
printf("ts.tv_sec: %ld, ts.tv_nsec: %ld\n",
|
||||
ts.tv_sec, ts.tv_nsec);
|
||||
exit(PTS_FAIL);
|
||||
}
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
#if _POSIX_THREAD_CPUTIME == -1
|
||||
printf("_POSIX_THREAD_CPUTIME not supported\n");
|
||||
return PTS_UNSUPPORTED;
|
||||
#endif
|
||||
pthread_t new_th;
|
||||
|
||||
if (sysconf(_SC_THREAD_CPUTIME) == -1) {
|
||||
printf("_POSIX_THREAD_CPUTIME not supported\n");
|
||||
return PTS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if(pthread_create(&new_th, NULL, a_thread_func, NULL) != 0)
|
||||
{
|
||||
perror("Error creating thread\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
pthread_join(new_th, NULL);
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
|
||||
* Test pthread_create()
|
||||
*
|
||||
* If success, pthread_create() returns zero.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Create a thread using pthread_create(), passing to it all valid values.
|
||||
* 2. If the return code was not EGAIN, EPERM or EINVAL, it should return 0.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
/* Thread starting routine that really does nothing. */
|
||||
void *a_thread_func()
|
||||
{
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t new_th;
|
||||
int ret;
|
||||
|
||||
/* Create new thread and check the return value. */
|
||||
ret = pthread_create(&new_th, NULL, a_thread_func, NULL);
|
||||
if(ret != 0)
|
||||
{
|
||||
if((ret != EINVAL) && (ret != EAGAIN) && (ret != EPERM))
|
||||
|
||||
printf("Test FAILED: Wrong return code: %d\n", ret);
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
|
||||
|
||||
+333
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Bull S.A.. All rights reserved.
|
||||
* Created by: Sebastien Decugis
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it would be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
|
||||
|
||||
* This sample test aims to check the following assertion:
|
||||
*
|
||||
* The function does not return EINTR
|
||||
|
||||
* The steps are:
|
||||
* -> pthread_kill a thread which creates threads
|
||||
* -> check that EINTR is never returned
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
/* Some routines are part of the XSI Extensions */
|
||||
#ifndef WITHOUT_XOPEN
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
/********************************************************************************************/
|
||||
/****************************** standard includes *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sched.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
|
||||
/********************************************************************************************/
|
||||
/****************************** Test framework *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include "testfrmw.h"
|
||||
#include "testfrmw.c"
|
||||
/* This header is responsible for defining the following macros:
|
||||
* UNRESOLVED(ret, descr);
|
||||
* where descr is a description of the error and ret is an int (error code for example)
|
||||
* FAILED(descr);
|
||||
* where descr is a short text saying why the test has failed.
|
||||
* PASSED();
|
||||
* No parameter.
|
||||
*
|
||||
* Both three macros shall terminate the calling process.
|
||||
* The testcase shall not terminate in any other maneer.
|
||||
*
|
||||
* The other file defines the functions
|
||||
* void output_init()
|
||||
* void output(char * string, ...)
|
||||
*
|
||||
* Those may be used to output information.
|
||||
*/
|
||||
|
||||
/********************************************************************************************/
|
||||
/********************************** Configuration ******************************************/
|
||||
/********************************************************************************************/
|
||||
#ifndef VERBOSE
|
||||
#define VERBOSE 1
|
||||
#endif
|
||||
|
||||
#define WITH_SYNCHRO
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Test cases *****************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
#include "threads_scenarii.c"
|
||||
|
||||
/* This file will define the following objects:
|
||||
* scenarii: array of struct __scenario type.
|
||||
* NSCENAR : macro giving the total # of scenarii
|
||||
* scenar_init(): function to call before use the scenarii array.
|
||||
* scenar_fini(): function to call after end of use of the scenarii array.
|
||||
*/
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Real Test *****************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
char do_it=1;
|
||||
char woken=0;
|
||||
unsigned long count_ope=0;
|
||||
#ifdef WITH_SYNCHRO
|
||||
sem_t semsig1;
|
||||
sem_t semsig2;
|
||||
unsigned long count_sig=0;
|
||||
#endif
|
||||
|
||||
sigset_t usersigs;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int sig;
|
||||
#ifdef WITH_SYNCHRO
|
||||
sem_t *sem;
|
||||
#endif
|
||||
} thestruct;
|
||||
|
||||
/* the following function keeps on sending the signal to the process */
|
||||
void * sendsig (void * arg)
|
||||
{
|
||||
thestruct *thearg = (thestruct *) arg;
|
||||
int ret;
|
||||
pid_t process;
|
||||
|
||||
process=getpid();
|
||||
|
||||
/* We block the signals SIGUSR1 and SIGUSR2 for this THREAD */
|
||||
ret = pthread_sigmask(SIG_BLOCK, &usersigs, NULL);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to block SIGUSR1 and SIGUSR2 in signal thread"); }
|
||||
|
||||
while (do_it)
|
||||
{
|
||||
#ifdef WITH_SYNCHRO
|
||||
if ((ret = sem_wait(thearg->sem)))
|
||||
{ UNRESOLVED(errno, "Sem_wait in sendsig"); }
|
||||
count_sig++;
|
||||
#endif
|
||||
|
||||
ret = kill(process, thearg->sig);
|
||||
if (ret != 0) { UNRESOLVED(errno, "Kill in sendsig"); }
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Next are the signal handlers. */
|
||||
/* This one is registered for signal SIGUSR1 */
|
||||
void sighdl1(int sig)
|
||||
{
|
||||
#ifdef WITH_SYNCHRO
|
||||
if (sem_post(&semsig1))
|
||||
{ UNRESOLVED(errno, "Sem_post in signal handler 1"); }
|
||||
#endif
|
||||
}
|
||||
/* This one is registered for signal SIGUSR2 */
|
||||
void sighdl2(int sig)
|
||||
{
|
||||
#ifdef WITH_SYNCHRO
|
||||
if (sem_post(&semsig2))
|
||||
{ UNRESOLVED(errno, "Sem_post in signal handler 2"); }
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Thread function -- almost does nothing */
|
||||
void * threaded(void * arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Signal we're done (especially in case of a detached thread) */
|
||||
do { ret = sem_post(&scenarii[sc].sem); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); }
|
||||
|
||||
/* return */
|
||||
return arg;
|
||||
}
|
||||
|
||||
/* Test function -- creates the threads and check that EINTR is never returned. */
|
||||
void * test(void * arg)
|
||||
{
|
||||
int ret=0;
|
||||
pthread_t child;
|
||||
|
||||
/* We don't block the signals SIGUSR1 and SIGUSR2 for this THREAD */
|
||||
ret = pthread_sigmask(SIG_UNBLOCK, &usersigs, NULL);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to unblock SIGUSR1 and SIGUSR2 in worker thread"); }
|
||||
|
||||
sc = 0;
|
||||
|
||||
while (do_it)
|
||||
{
|
||||
#if VERBOSE > 5
|
||||
output("-----\n");
|
||||
output("Starting test with scenario (%i): %s\n", sc, scenarii[sc].descr);
|
||||
#endif
|
||||
|
||||
count_ope++;
|
||||
|
||||
ret = pthread_create(&child, &scenarii[sc].ta, threaded, NULL);
|
||||
if (ret == EINTR) { FAILED("pthread_create returned EINTR"); }
|
||||
switch (scenarii[sc].result)
|
||||
{
|
||||
case 0: /* Operation was expected to succeed */
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to create this thread"); }
|
||||
break;
|
||||
|
||||
case 1: /* Operation was expected to fail */
|
||||
if (ret == 0) { UNRESOLVED(-1, "An error was expected but the thread creation succeeded"); }
|
||||
break;
|
||||
|
||||
case 2: /* We did not know the expected result */
|
||||
default:
|
||||
#if VERBOSE > 5
|
||||
if (ret == 0)
|
||||
{ output("Thread has been created successfully for this scenario\n"); }
|
||||
else
|
||||
{ output("Thread creation failed with the error: %s\n", strerror(ret)); }
|
||||
#endif
|
||||
;
|
||||
}
|
||||
if (ret == 0) /* The new thread is running */
|
||||
{
|
||||
if (scenarii[sc].detached == 0)
|
||||
{
|
||||
ret = pthread_join(child, NULL);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to join a thread"); }
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just wait for the thread to terminate */
|
||||
do { ret = sem_wait(&scenarii[sc].sem); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); }
|
||||
}
|
||||
}
|
||||
|
||||
/* Change thread attribute for the next loop */
|
||||
sc++;
|
||||
sc %= NSCENAR;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Main function */
|
||||
int main (int argc, char * argv[])
|
||||
{
|
||||
int ret;
|
||||
pthread_t th_work, th_sig1, th_sig2;
|
||||
thestruct arg1, arg2;
|
||||
struct sigaction sa;
|
||||
|
||||
/* Initialize output routine */
|
||||
output_init();
|
||||
|
||||
/* Initialize thread attribute objects */
|
||||
scenar_init();
|
||||
|
||||
/* We need to register the signal handlers for the PROCESS */
|
||||
sigemptyset (&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = sighdl1;
|
||||
if ((ret = sigaction (SIGUSR1, &sa, NULL)))
|
||||
{ UNRESOLVED(ret, "Unable to register signal handler1"); }
|
||||
sa.sa_handler = sighdl2;
|
||||
if ((ret = sigaction (SIGUSR2, &sa, NULL)))
|
||||
{ UNRESOLVED(ret, "Unable to register signal handler2"); }
|
||||
|
||||
/* We prepare a signal set which includes SIGUSR1 and SIGUSR2 */
|
||||
sigemptyset(&usersigs);
|
||||
ret = sigaddset(&usersigs, SIGUSR1);
|
||||
ret |= sigaddset(&usersigs, SIGUSR2);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to add SIGUSR1 or 2 to a signal set"); }
|
||||
|
||||
/* We now block the signals SIGUSR1 and SIGUSR2 for this THREAD */
|
||||
ret = pthread_sigmask(SIG_BLOCK, &usersigs, NULL);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to block SIGUSR1 and SIGUSR2 in main thread"); }
|
||||
|
||||
#ifdef WITH_SYNCHRO
|
||||
if (sem_init(&semsig1, 0, 1))
|
||||
{ UNRESOLVED(errno, "Semsig1 init"); }
|
||||
if (sem_init(&semsig2, 0, 1))
|
||||
{ UNRESOLVED(errno, "Semsig2 init"); }
|
||||
#endif
|
||||
|
||||
if ((ret = pthread_create(&th_work, NULL, test, NULL)))
|
||||
{ UNRESOLVED(ret, "Worker thread creation failed"); }
|
||||
|
||||
arg1.sig = SIGUSR1;
|
||||
arg2.sig = SIGUSR2;
|
||||
#ifdef WITH_SYNCHRO
|
||||
arg1.sem = &semsig1;
|
||||
arg2.sem = &semsig2;
|
||||
#endif
|
||||
|
||||
if ((ret = pthread_create(&th_sig1, NULL, sendsig, (void *)&arg1)))
|
||||
{ UNRESOLVED(ret, "Signal 1 sender thread creation failed"); }
|
||||
if ((ret = pthread_create(&th_sig2, NULL, sendsig, (void *)&arg2)))
|
||||
{ UNRESOLVED(ret, "Signal 2 sender thread creation failed"); }
|
||||
|
||||
/* Let's wait for a while now */
|
||||
sleep(1);
|
||||
|
||||
/* Now stop the threads and join them */
|
||||
do { do_it=0; }
|
||||
while (do_it);
|
||||
|
||||
if ((ret = pthread_join(th_sig1, NULL)))
|
||||
{ UNRESOLVED(ret, "Signal 1 sender thread join failed"); }
|
||||
if ((ret = pthread_join(th_sig2, NULL)))
|
||||
{ UNRESOLVED(ret, "Signal 2 sender thread join failed"); }
|
||||
|
||||
if ((ret = pthread_join(th_work, NULL)))
|
||||
{ UNRESOLVED(ret, "Worker thread join failed"); }
|
||||
|
||||
scenar_fini();
|
||||
|
||||
#if VERBOSE > 0
|
||||
output("Test executed successfully.\n");
|
||||
output(" %d thread creations.\n", count_ope);
|
||||
#ifdef WITH_SYNCHRO
|
||||
output(" %d signals were sent meanwhile.\n", count_sig);
|
||||
#endif
|
||||
#endif
|
||||
PASSED;
|
||||
}
|
||||
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Bull S.A.. All rights reserved.
|
||||
* Created by: Sebastien Decugis
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it would be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
|
||||
|
||||
* This sample test aims to check the following assertion:
|
||||
*
|
||||
* If the current thread has an alternate stack, the new thread does not inherit
|
||||
* this stack
|
||||
|
||||
* The steps are:
|
||||
* -> Create a thread with an alternate stack.
|
||||
* -> From this thread, create another thread.
|
||||
* -> Check that the new thread does not use the same stack.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
/* Some routines are part of the XSI Extensions */
|
||||
#ifndef WITHOUT_XOPEN
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
/********************************************************************************************/
|
||||
/****************************** standard includes *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sched.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
/****************************** Test framework *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include "testfrmw.h"
|
||||
#include "testfrmw.c"
|
||||
/* This header is responsible for defining the following macros:
|
||||
* UNRESOLVED(ret, descr);
|
||||
* where descr is a description of the error and ret is an int (error code for example)
|
||||
* FAILED(descr);
|
||||
* where descr is a short text saying why the test has failed.
|
||||
* PASSED();
|
||||
* No parameter.
|
||||
*
|
||||
* Both three macros shall terminate the calling process.
|
||||
* The testcase shall not terminate in any other maneer.
|
||||
*
|
||||
* The other file defines the functions
|
||||
* void output_init()
|
||||
* void output(char * string, ...)
|
||||
*
|
||||
* Those may be used to output information.
|
||||
*/
|
||||
|
||||
/********************************************************************************************/
|
||||
/********************************** Configuration ******************************************/
|
||||
/********************************************************************************************/
|
||||
#ifndef VERBOSE
|
||||
#define VERBOSE 1
|
||||
#endif
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Test cases *****************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
#define STD_MAIN
|
||||
#include "threads_scenarii.c"
|
||||
|
||||
/* This file will define the following objects:
|
||||
* scenarii: array of struct __scenario type.
|
||||
* NSCENAR : macro giving the total # of scenarii
|
||||
* scenar_init(): function to call before use the scenarii array.
|
||||
* scenar_fini(): function to call after end of use of the scenarii array.
|
||||
*/
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Real Test *****************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
void * teststack(void * arg)
|
||||
{
|
||||
int ret=0;
|
||||
*(int **)arg = &ret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Thread function */
|
||||
void * threaded(void * arg)
|
||||
{
|
||||
int ret;
|
||||
int * child_stack;
|
||||
pthread_t gchild;
|
||||
|
||||
int sz = sysconf(_SC_THREAD_STACK_MIN);
|
||||
|
||||
if (scenarii[sc].bottom != NULL)
|
||||
{
|
||||
#if VERBOSE > 1
|
||||
output("Processing test\n");
|
||||
#endif
|
||||
|
||||
/* Create a new thread and get a location inside its stack */
|
||||
ret = pthread_create(&gchild, NULL, teststack, &child_stack);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to create a thread with default attribute"); }
|
||||
|
||||
ret = pthread_join(gchild, NULL);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to join the test thread"); }
|
||||
|
||||
/* Check the new thread stack location was outside of the current thread location */
|
||||
/* We convert all the @ to longs */
|
||||
#if VERBOSE > 4
|
||||
output("Current stack : %p -> %p\n", scenarii[sc].bottom, sz + (long)scenarii[sc].bottom);
|
||||
output("Child location: %p\n", child_stack);
|
||||
#endif
|
||||
|
||||
if ( (((long)scenarii[sc].bottom) < ((long)child_stack))
|
||||
&& (((long)child_stack) < (((long)scenarii[sc].bottom) + sz)))
|
||||
{
|
||||
FAILED("The new thread inherited th alternate stack from its parent");
|
||||
}
|
||||
}
|
||||
|
||||
/* Signal we're done (especially in case of a detached thread) */
|
||||
do { ret = sem_post(&scenarii[sc].sem); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); }
|
||||
|
||||
/* return */
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
|
||||
* Test If 'attr' is NULL, the default attributes shall be used.
|
||||
* The attribute that will be tested is the detached state, because that is
|
||||
* the only state that has a default listed in the specification.
|
||||
*
|
||||
* default: PTHREAD_CREATE_JOINABLE
|
||||
* Other valid values: PTHREAD_CREATE_DETACHED
|
||||
|
||||
*
|
||||
* Steps:
|
||||
* 1. Create a thread using pthread_create() and passing 'NULL' for 'attr'.
|
||||
* 2. Check to see if the thread is joinable, since that is the default.
|
||||
* 3. We do this by calling pthread_join() and pthread_detach(). If
|
||||
* they fail, then the thread is not joinable, and the test fails.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
void *a_thread_func()
|
||||
{
|
||||
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t new_th;
|
||||
|
||||
/* Create a new thread. The default attribute should be that
|
||||
* it is joinable. */
|
||||
if(pthread_create(&new_th, NULL, a_thread_func, NULL) != 0)
|
||||
{
|
||||
perror("Error creating thread\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* The new thread should be able to be joined. */
|
||||
if(pthread_join(new_th, NULL) == EINVAL)
|
||||
{
|
||||
printf("Test FAILED\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
/* The new thread should be able to be detached. */
|
||||
if(pthread_detach(new_th) == EINVAL)
|
||||
{
|
||||
printf("Test FAILED\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
|
||||
* Test if the attributes specified by 'attr' are modified later, the thread's
|
||||
* attributes shall not be affected.
|
||||
* The attribute that will be tested is the detached state.
|
||||
*
|
||||
*
|
||||
* Steps:
|
||||
* 1. Set a pthread_attr_t object to be PTHREAD_CREATE_JOINABLE.
|
||||
* 2. Create a new thread using pthread_create() and passing this attribute
|
||||
* object.
|
||||
* 3. Change the attribute object to be in a detached state rather than
|
||||
* joinable.
|
||||
* 4. Doing this should not effect the fact that the thread that was created
|
||||
* is joinable, and so calling the functions pthread_detach() should not fail.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
# define TIMEOUT 10 /* Timeout value of 10 seconds. */
|
||||
# define INTHREAD 0 /* Control going to or is already for Thread */
|
||||
# define INMAIN 1 /* Control going to or is already for Main */
|
||||
|
||||
int sem1; /* Manual semaphore */
|
||||
|
||||
void *a_thread_func()
|
||||
{
|
||||
/* Indicate to main() that the thread was created. */
|
||||
sem1=INTHREAD;
|
||||
|
||||
/* Wait for main to detach change the attribute object and try and detach this thread.
|
||||
* Wait for a timeout value of 10 seconds before timing out if the thread was not able
|
||||
* to be detached. */
|
||||
sleep(TIMEOUT);
|
||||
|
||||
printf("Test FAILED: Did not detach the thread, main still waiting for it to end execution.\n");
|
||||
pthread_exit((void*)PTS_FAIL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t new_th;
|
||||
pthread_attr_t new_attr;
|
||||
int ret;
|
||||
|
||||
/* Initializing */
|
||||
sem1 = INMAIN;
|
||||
if(pthread_attr_init(&new_attr) != 0)
|
||||
{
|
||||
perror("Error intializing attribute object\n");
|
||||
return PTS_UNRESOLVED;
|
||||
|
||||
}
|
||||
|
||||
/* Make the new attribute object joinable */
|
||||
if(pthread_attr_setdetachstate(&new_attr, PTHREAD_CREATE_JOINABLE) != 0)
|
||||
{
|
||||
perror("Error setting the detached state of the attribute\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Create a new thread and pass it the attribute object that will
|
||||
* make it joinable. */
|
||||
if(pthread_create(&new_th, &new_attr, a_thread_func, NULL) != 0)
|
||||
{
|
||||
perror("Error creating thread\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
while(sem1==INMAIN)
|
||||
sleep(1);
|
||||
|
||||
/* Now change the attribute object to be in a detached state */
|
||||
if(pthread_attr_setdetachstate(&new_attr, PTHREAD_CREATE_DETACHED) != 0)
|
||||
{
|
||||
perror("Error setting the detached state of the attribute\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* The new thread should still be able to be detached. */
|
||||
if((ret=pthread_detach(new_th)) == EINVAL)
|
||||
{
|
||||
printf("Test FAILED: pthread_detach failed on joinable thread. Return value is %d\n", ret);
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
|
||||
|
||||
+649
@@ -0,0 +1,649 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Bull S.A.. All rights reserved.
|
||||
* Created by: Sebastien Decugis
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it would be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
|
||||
|
||||
* This sample test aims to check the following assertion:
|
||||
*
|
||||
* Once the thread has been created, subsequent changes to the
|
||||
* thread attribute object don't affect the running thread.
|
||||
|
||||
* The steps are:
|
||||
* -> stack grow
|
||||
* -> create a thread with minimal stack size
|
||||
* -> change the stack size to a bigger value
|
||||
* -> check that the thread stack size did not change.
|
||||
* -> stack decrease
|
||||
* -> create a thread with a known stack size (> minimum)
|
||||
* -> change the stack size to the min value
|
||||
* -> check that the thread stack size did not change.
|
||||
* -> sched policy/param change
|
||||
* -> create a new thread with a known policy
|
||||
* -> change the policy in the thread attribute and check the thread policy did not change
|
||||
* -> change the schedparam in the thread attribute and check the thread priority did not change
|
||||
* -> change the policy in the running thread and check the thread attribute did not change.
|
||||
* -> change the priority in the running thread and check the thread attribute did not change.
|
||||
|
||||
* The test fails if one of the checking fails
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
/* Some routines are part of the XSI Extensions */
|
||||
#ifndef WITHOUT_XOPEN
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
/********************************************************************************************/
|
||||
/****************************** standard includes *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sched.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
/****************************** Test framework *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include "testfrmw.h"
|
||||
#include "testfrmw.c"
|
||||
/* This header is responsible for defining the following macros:
|
||||
* UNRESOLVED(ret, descr);
|
||||
* where descr is a description of the error and ret is an int (error code for example)
|
||||
* FAILED(descr);
|
||||
* where descr is a short text saying why the test has failed.
|
||||
* PASSED();
|
||||
* No parameter.
|
||||
*
|
||||
* Both three macros shall terminate the calling process.
|
||||
* The testcase shall not terminate in any other maneer.
|
||||
*
|
||||
* The other file defines the functions
|
||||
* void output_init()
|
||||
* void output(char * string, ...)
|
||||
*
|
||||
* Those may be used to output information.
|
||||
*/
|
||||
|
||||
/********************************************************************************************/
|
||||
/********************************** Configuration ******************************************/
|
||||
/********************************************************************************************/
|
||||
#ifndef VERBOSE
|
||||
#define VERBOSE 1
|
||||
#endif
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Test cases *****************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
#include "threads_scenarii.c"
|
||||
|
||||
/* This file will define the following objects:
|
||||
* scenarii: array of struct __scenario type.
|
||||
* NSCENAR : macro giving the total # of scenarii
|
||||
* scenar_init(): function to call before use the scenarii array.
|
||||
* scenar_fini(): function to call after end of use of the scenarii array.
|
||||
*/
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Real Test *****************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
sem_t semsync[2]; /* These semaphores will only be used in child process! */
|
||||
|
||||
/* The overflow function is used to test the stack overflow */
|
||||
void * overflow(void * arg)
|
||||
{
|
||||
void * current;
|
||||
void * pad[50]; /* We want to consume the stack quickly */
|
||||
long stacksize = sysconf(_SC_THREAD_STACK_MIN); /* make sure we touch the current stack memory */
|
||||
|
||||
pad[1]=NULL; /* so compiler stops complaining about unused variables */
|
||||
int ret = 0;
|
||||
|
||||
if (arg == NULL)
|
||||
{
|
||||
/* first call */
|
||||
|
||||
/* Synchronize with the parent */
|
||||
do { ret = sem_wait(&semsync[0]); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); }
|
||||
|
||||
|
||||
/* Go to recursion */
|
||||
current = overflow(¤t);
|
||||
|
||||
/* Terminated */
|
||||
do { ret = sem_post(&semsync[1]); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); }
|
||||
|
||||
/* Terminate the overflow thread */
|
||||
return current;
|
||||
}
|
||||
|
||||
/* we cast the pointers into long, which might be a problem on some architectures... */
|
||||
if ( ((long)arg) < ((long)¤t))
|
||||
{
|
||||
/* the stack is growing up */
|
||||
if ( ((long)¤t) - ((long)arg) >= stacksize)
|
||||
{
|
||||
output("Growing up stack started below %p and we are currently up to %p\n", arg, ¤t);
|
||||
return (void *)0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the stack is growing down */
|
||||
if ( ((long)arg) - ((long)¤t) >= stacksize)
|
||||
{
|
||||
output("Growing down stack started upon %p and we are currently down to %p\n", arg, ¤t);
|
||||
return (void *)0;
|
||||
}
|
||||
}
|
||||
|
||||
/* We are not yet overflowing, so we loop */
|
||||
return overflow(arg);
|
||||
}
|
||||
|
||||
/* The following function will return
|
||||
0 if a thread created with the attribute ta is able to fill the stack up to {minstacksize}.
|
||||
1 if the operation failed.
|
||||
2 if an error prevented the test to complete
|
||||
|
||||
If newsize is not 0, the stack size in ta will be set to this value once the thread is created.
|
||||
|
||||
*/
|
||||
int test_stack(pthread_attr_t * ta, size_t newsize)
|
||||
{
|
||||
pid_t child, ctrl;
|
||||
int status;
|
||||
int ret;
|
||||
|
||||
child=fork(); /* We'll test the feature in another process as this test may segfault */
|
||||
|
||||
if (child == -1)
|
||||
{
|
||||
output("Failed to fork (%s)\n", strerror(errno));
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (child != 0) /* father */
|
||||
{
|
||||
/* Just wait for the child and check its return value */
|
||||
ctrl = waitpid(child, &status, 0);
|
||||
if (ctrl != child)
|
||||
{
|
||||
output("Failed to wait for process termination (%s)\n", strerror(errno));
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (WIFEXITED(status)) /* The process exited */
|
||||
{
|
||||
if (WEXITSTATUS(status) == 0)
|
||||
{ return 0; } /* We were able to fill the stack */
|
||||
if (WEXITSTATUS(status) == PTS_UNRESOLVED)
|
||||
{
|
||||
output("The child process returned unresolved status\n");
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
output("The child process returned: %i\n", WEXITSTATUS(status));
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if VERBOSE > 4
|
||||
output("The child process did not return\n");
|
||||
if (WIFSIGNALED(status))
|
||||
output("It was killed with signal %i\n", WTERMSIG(status));
|
||||
else
|
||||
output("neither was it killed. (status = %i)\n", status);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* else */
|
||||
/* this is the new process */
|
||||
{
|
||||
pthread_t th;
|
||||
void * rc;
|
||||
int detach;
|
||||
|
||||
/* Semaphore to force the child to wait */
|
||||
ret = sem_init(&semsync[0], 0,0);
|
||||
if (ret == -1) { UNRESOLVED(errno, "Unable to init a semaphore"); }
|
||||
/* Semaphore to detect thread ending */
|
||||
ret = sem_init(&semsync[1], 0,0);
|
||||
if (ret == -1) { UNRESOLVED(errno, "Unable to init a semaphore"); }
|
||||
|
||||
ret = pthread_create(&th, ta, overflow, NULL); /* Create a new thread with the same attributes */
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to create a thread in the new process"); }
|
||||
|
||||
/* If we were asked to perform a change on ta, do it now. */
|
||||
if (newsize)
|
||||
{
|
||||
ret = pthread_attr_setstacksize(ta, newsize);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to set the new stack size"); }
|
||||
}
|
||||
|
||||
/* Ok the child can run now */
|
||||
do { ret = sem_post(&semsync[0]); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); }
|
||||
|
||||
|
||||
/* Wait for its termination */
|
||||
do { ret = sem_wait(&semsync[1]); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); }
|
||||
|
||||
if (ta != NULL)
|
||||
{
|
||||
ret = pthread_attr_getdetachstate(ta, &detach);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to get detach state from the thread attribute"); }
|
||||
}
|
||||
else
|
||||
{
|
||||
detach = PTHREAD_CREATE_JOINABLE; /* default */
|
||||
}
|
||||
|
||||
if (detach == PTHREAD_CREATE_JOINABLE)
|
||||
{
|
||||
ret = pthread_join(th, &rc);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to join a thread"); }
|
||||
if (rc != (void *)0)
|
||||
{ UNRESOLVED((int)(long)rc, "The overflow function returned an unexpected value"); }
|
||||
}
|
||||
|
||||
|
||||
/* Terminate the child process here */
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
pthread_barrier_t bar;
|
||||
int policy;
|
||||
struct sched_param param;
|
||||
} testdata_t;
|
||||
|
||||
void * schedtest(void * arg)
|
||||
{
|
||||
testdata_t * td = (testdata_t *)arg;
|
||||
int newpol, ret=0;
|
||||
struct sched_param newparam;
|
||||
|
||||
/* Read the current sched policy & param */
|
||||
ret = pthread_getschedparam(pthread_self(), &(td->policy), &(td->param));
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to read current thread policy / param"); }
|
||||
|
||||
/* sync 1 */
|
||||
ret = pthread_barrier_wait(&(td->bar));
|
||||
if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); }
|
||||
|
||||
/* sync 2 */
|
||||
ret = pthread_barrier_wait(&(td->bar));
|
||||
if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); }
|
||||
|
||||
/* Read the current sched policy & param */
|
||||
ret = pthread_getschedparam(pthread_self(), &(td->policy), &(td->param));
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to read current thread policy / param"); }
|
||||
|
||||
/* sync 3 */
|
||||
ret = pthread_barrier_wait(&(td->bar));
|
||||
if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); }
|
||||
|
||||
/* sync 4 */
|
||||
ret = pthread_barrier_wait(&(td->bar));
|
||||
if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); }
|
||||
|
||||
/* Change the current sched policy & param */
|
||||
if (td->policy == SCHED_RR)
|
||||
newpol = SCHED_FIFO;
|
||||
else
|
||||
newpol = SCHED_RR;
|
||||
|
||||
newparam.sched_priority = sched_get_priority_max(newpol);
|
||||
|
||||
if (newparam.sched_priority == td->param.sched_priority)
|
||||
newparam.sched_priority--;
|
||||
|
||||
ret = pthread_setschedparam(pthread_self(), newpol, &newparam);
|
||||
#if VERBOSE > 0
|
||||
if (ret != 0)
|
||||
output("Changing the current thread sched policy failed with error: %s\n", strerror(ret));
|
||||
#endif
|
||||
#if VERBOSE > 2
|
||||
else
|
||||
output("Executing thread scheduling policy changed\n");
|
||||
#endif
|
||||
|
||||
/* sync 5 */
|
||||
ret = pthread_barrier_wait(&(td->bar));
|
||||
if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); }
|
||||
|
||||
/* Post the sem in case of a detached thread */
|
||||
do { ret = sem_post(&scenarii[sc].sem); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); }
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int ret=0;
|
||||
int do_stack_tests;
|
||||
int do_sched_tests;
|
||||
|
||||
/* Initialize output routine */
|
||||
output_init();
|
||||
|
||||
/* Test abilities */
|
||||
do_sched_tests = (sysconf(_SC_THREAD_PRIORITY_SCHEDULING)>0?1:0);
|
||||
do_stack_tests = (test_stack(NULL,0)==0?1:0);
|
||||
#if VERBOSE > 0
|
||||
output("Test starting\n Stack tests %s be executed.\n Sched tests %s be executed.\n",
|
||||
do_stack_tests?"will":"won't",
|
||||
do_sched_tests?"will":"won't");
|
||||
#endif
|
||||
|
||||
/* Initialize thread attribute objects */
|
||||
scenar_init();
|
||||
|
||||
for (sc=0; sc < NSCENAR; sc++)
|
||||
{
|
||||
#if VERBOSE > 0
|
||||
output("-----\n");
|
||||
output("Starting test with scenario (%i): %s\n", sc, scenarii[sc].descr);
|
||||
#endif
|
||||
|
||||
if (do_stack_tests)
|
||||
{
|
||||
/* stack grow test */
|
||||
/* We need the thread attribute to specify a minimal stack */
|
||||
if ((scenarii[sc].altstack == 0) && (scenarii[sc].altsize == 1))
|
||||
{
|
||||
#if VERBOSE > 2
|
||||
output("Processing stack grow test\n");
|
||||
#endif
|
||||
|
||||
ret = test_stack(&scenarii[sc].ta, 2*sysconf(_SC_THREAD_STACK_MIN));
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
if (scenarii[sc].guard == 2)
|
||||
{
|
||||
FAILED("Changing the stacksize after the thread was created changed the running thread stack size");
|
||||
}
|
||||
#if VERBOSE > 2
|
||||
else
|
||||
output("We were able to overflow the stack, but the guard area is unknow or null\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if ((ret != 2) && (scenarii[sc].result == 1))
|
||||
{
|
||||
UNRESOLVED(-1, "An error was expected but the thread creation succeeded");
|
||||
}
|
||||
|
||||
#if VERBOSE > 2
|
||||
if ((ret == 1))
|
||||
{
|
||||
output("Stack grow test passed\n");
|
||||
}
|
||||
|
||||
if ((ret == 2) && (scenarii[sc].result == 2))
|
||||
{
|
||||
output("Something went wrong -- we don't care in this case\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((ret == 2) && (scenarii[sc].result == 0))
|
||||
{
|
||||
UNRESOLVED(-1, "An unexpected error occured\n");
|
||||
}
|
||||
|
||||
/* Ok, set back the thread attribute object to a correct value */
|
||||
ret = pthread_attr_setstacksize(&scenarii[sc].ta, sysconf(_SC_THREAD_STACK_MIN));
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to set stacksize back"); }
|
||||
}
|
||||
|
||||
|
||||
/* stack decrease test */
|
||||
if ((scenarii[sc].altstack == 0) && (scenarii[sc].altsize == 0))
|
||||
{
|
||||
#if VERBOSE > 2
|
||||
output("Processing stack decrease test\n");
|
||||
#endif
|
||||
|
||||
ret = test_stack(&scenarii[sc].ta, sysconf(_SC_THREAD_STACK_MIN));
|
||||
|
||||
if (ret == 1) { FAILED("Decreasing the stack size after thread is created had an influence on the thread"); }
|
||||
|
||||
if ((ret == 0) && (scenarii[sc].result == 1))
|
||||
{
|
||||
UNRESOLVED(-1, "An error was expected but the thread creation succeeded");
|
||||
}
|
||||
|
||||
if ((ret == 2) && (scenarii[sc].result == 0))
|
||||
{
|
||||
UNRESOLVED(-1, "An unexpected error occured\n");
|
||||
}
|
||||
|
||||
#if VERBOSE > 2
|
||||
if (ret == 0)
|
||||
output("Stack decrease test passed.\n");
|
||||
else
|
||||
output("Something failed but we don't care here.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
} /* if do_stack_tests */
|
||||
|
||||
if (do_sched_tests)
|
||||
{
|
||||
/* Sched policy/param change test */
|
||||
if (scenarii[sc].explicitsched != 0) /* We need a specified policy */
|
||||
{
|
||||
pthread_t child;
|
||||
int policy_ori, newpol_max;
|
||||
struct sched_param param_ori, tmp;
|
||||
|
||||
testdata_t td;
|
||||
|
||||
#if VERBOSE > 2
|
||||
output("Processing sched policy/param change test\n");
|
||||
#endif
|
||||
|
||||
/* Backup the scenario object */
|
||||
ret = pthread_attr_getschedpolicy(&(scenarii[sc].ta), &policy_ori);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to read sched policy from thread attribute"); }
|
||||
ret = pthread_attr_getschedparam(&(scenarii[sc].ta), ¶m_ori);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to read sched param from thread attribute"); }
|
||||
|
||||
/* Initialize the barrier */
|
||||
ret = pthread_barrier_init(&(td.bar), NULL, 2);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to initialize the barrier"); }
|
||||
|
||||
/* Create a new thread with this scenario attribute */
|
||||
ret = pthread_create(&child, &(scenarii[sc].ta), schedtest, &td);
|
||||
if (ret != 0)
|
||||
{
|
||||
if (scenarii[sc].result == 0)
|
||||
{ UNRESOLVED(ret , "Failed to create a thread"); }
|
||||
|
||||
#if VERBOSE > 2
|
||||
if (scenarii[sc].result == 2)
|
||||
{
|
||||
output("The thread creation failed -- we don't care\n");
|
||||
}
|
||||
if (scenarii[sc].result == 1)
|
||||
{
|
||||
output("The thread creation failed as expected\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else /* Thread created */
|
||||
{
|
||||
if (scenarii[sc].result == 1)
|
||||
{ UNRESOLVED(-1, "The thread was created where an error was expected"); }
|
||||
|
||||
#if VERBOSE > 2
|
||||
if (scenarii[sc].result == 2)
|
||||
output("Thread is created\n");
|
||||
#endif
|
||||
|
||||
/* sync 1 */
|
||||
ret = pthread_barrier_wait(&(td.bar));
|
||||
if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); }
|
||||
|
||||
/* Check the new thread reports the attributes */
|
||||
if (td.policy != policy_ori)
|
||||
{ FAILED("The new thread does not report the scheluling policy that was specified"); }
|
||||
|
||||
if (td.param.sched_priority != param_ori.sched_priority)
|
||||
{ FAILED("The new thread does not report the scheduling priority that was specified at creation"); }
|
||||
|
||||
/* Change the thread attribute object policy & param */
|
||||
if (policy_ori == SCHED_RR)
|
||||
{
|
||||
ret = pthread_attr_setschedpolicy(&(scenarii[sc].ta), SCHED_FIFO);
|
||||
newpol_max = sched_get_priority_max(SCHED_FIFO);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = pthread_attr_setschedpolicy(&(scenarii[sc].ta), SCHED_RR);
|
||||
newpol_max = sched_get_priority_max(SCHED_RR);
|
||||
}
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to change the attribute object"); }
|
||||
|
||||
if (newpol_max == param_ori.sched_priority)
|
||||
newpol_max--;
|
||||
|
||||
tmp.sched_priority = newpol_max;
|
||||
|
||||
ret = pthread_attr_setschedparam(&(scenarii[sc].ta), &tmp);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to set the attribute sched param"); }
|
||||
|
||||
/* sync 2 */
|
||||
ret = pthread_barrier_wait(&(td.bar));
|
||||
if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); }
|
||||
|
||||
/* sync 3 */
|
||||
ret = pthread_barrier_wait(&(td.bar));
|
||||
if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); }
|
||||
|
||||
/* Check if the thread saw the change (should not) */
|
||||
if (td.policy != policy_ori)
|
||||
{ FAILED("The new thread does not report the scheluling policy that was specified"); }
|
||||
|
||||
if (td.param.sched_priority != param_ori.sched_priority)
|
||||
{ FAILED("The new thread does not report the scheduling priority that was specified at creation"); }
|
||||
|
||||
/* Check what we can see for the child thread from here */
|
||||
ret = pthread_getschedparam(child, &(td.policy), &(td.param));
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to read child thread policy / param"); }
|
||||
|
||||
if (td.policy != policy_ori)
|
||||
{ FAILED("The child thread does not report the scheduling policy that was specified at creation"); }
|
||||
|
||||
if (td.param.sched_priority != param_ori.sched_priority)
|
||||
{ FAILED("The child thread does not report the scheduling priority that was specified at creation"); }
|
||||
|
||||
/* Restore the thread attribute */
|
||||
ret = pthread_attr_setschedpolicy(&(scenarii[sc].ta), policy_ori);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to read sched policy from thread attribute"); }
|
||||
ret = pthread_attr_setschedparam(&(scenarii[sc].ta), ¶m_ori);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to read sched param from thread attribute"); }
|
||||
|
||||
/* sync 4*/
|
||||
ret = pthread_barrier_wait(&(td.bar));
|
||||
if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); }
|
||||
|
||||
/* sync 5*/
|
||||
ret = pthread_barrier_wait(&(td.bar));
|
||||
if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); }
|
||||
|
||||
/* check if the thread attribute reports a change (should not) */
|
||||
ret = pthread_attr_getschedpolicy(&(scenarii[sc].ta), &(td.policy));
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to read sched policy from thread attribute"); }
|
||||
ret = pthread_attr_getschedparam(&(scenarii[sc].ta), &(td.param));
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to read sched param from thread attribute"); }
|
||||
|
||||
if (td.policy != policy_ori)
|
||||
{ FAILED("The child thread does not report the scheduling policy that was specified at creation"); }
|
||||
|
||||
if (td.param.sched_priority != param_ori.sched_priority)
|
||||
{ FAILED("The child thread does not report the scheduling priority that was specified at creation"); }
|
||||
|
||||
/* Wait for the sem and join eventually the thread */
|
||||
do { ret = sem_wait(&scenarii[sc].sem); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); }
|
||||
|
||||
if (scenarii[sc].detached == 0)
|
||||
{
|
||||
ret = pthread_join(child, NULL);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to join a thread"); }
|
||||
}
|
||||
|
||||
#if VERBOSE > 2
|
||||
output("Sched policy/param change test passed\n");
|
||||
#endif
|
||||
} /* thread created */
|
||||
}
|
||||
|
||||
/* We could also test if the inheritsched does not influence the new thread */
|
||||
|
||||
} /* if do_sched_tests */
|
||||
}
|
||||
|
||||
scenar_fini();
|
||||
#if VERBOSE > 0
|
||||
output("-----\n");
|
||||
output("All test data destroyed\n");
|
||||
output("Test PASSED\n");
|
||||
#endif
|
||||
|
||||
PASSED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
*
|
||||
* Test upon successful completion, pthread_create() shall store the ID of the
|
||||
* the created thread in the location referenced by 'thread'.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Create a thread using pthread_create()
|
||||
* 2. Save the thread ID resulting from pthread_create()
|
||||
* 3. Get the thread ID from the new thread by calling
|
||||
* pthread_self().
|
||||
* 4. These 2 values should be equal. (i.e. the one from pthread_create()
|
||||
* and the one from pthread_self()).
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
void *a_thread_func();
|
||||
|
||||
pthread_t self_th; /* Save the value of the function call pthread_self()
|
||||
within the thread. Keeping it global so 'main' can
|
||||
see it too. */
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t new_th;
|
||||
|
||||
/* Create a new thread */
|
||||
if(pthread_create(&new_th, NULL, a_thread_func, NULL) != 0)
|
||||
{
|
||||
perror("Error creating thread\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Wait for the thread function to return to make sure we got
|
||||
* the thread ID value from pthread_self(). */
|
||||
if(pthread_join(new_th, NULL) != 0)
|
||||
{
|
||||
perror("Error calling pthread_join()\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* If the value of pthread_self() and the return value from
|
||||
* pthread_create() is equal, then the test passes. */
|
||||
if(pthread_equal(new_th, self_th) == 0)
|
||||
{
|
||||
printf("Test FAILED\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
|
||||
/* The thread function that calls pthread_self() to obtain its thread ID */
|
||||
void *a_thread_func()
|
||||
{
|
||||
self_th=pthread_self();
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
|
||||
* Test pthread_create()
|
||||
* The thread is created executing 'start_routine' with 'arg' as its only
|
||||
* argument.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Create 5 separete threads using pthread_create() passing to it a single int 'arg'.
|
||||
* 2. Use that passed int argument in the thread function start routine and make sure no
|
||||
* errors occur.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
#define NUM_THREADS 5
|
||||
|
||||
/* The thread start routine. */
|
||||
void *a_thread_func(void* num)
|
||||
{
|
||||
intptr_t i = (intptr_t) num;
|
||||
printf("Passed argument for thread: %d\n", (int)i);
|
||||
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t new_th;
|
||||
long i;
|
||||
|
||||
for(i=1;i<NUM_THREADS+1;i++)
|
||||
{
|
||||
if(pthread_create(&new_th, NULL, a_thread_func, (void*)i) != 0)
|
||||
{
|
||||
printf("Error creating thread\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
/* Wait for thread to end execution */
|
||||
pthread_join(new_th, NULL);
|
||||
}
|
||||
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
|
||||
* Test pthread_create()
|
||||
* The thread is created executing 'start_routine' with 'arg' as its only
|
||||
* argument.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Create a thread using pthread_create() passing to it an array of 'int's as an argument.
|
||||
* 2. Use that passed int argument in the thread function start routine and make sure no
|
||||
* errors occur.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
#define NUM_THREADS 5
|
||||
|
||||
/* The thread start routine. */
|
||||
void *a_thread_func(void* num)
|
||||
{
|
||||
int *i, j;
|
||||
|
||||
i = (int *)num;
|
||||
|
||||
for(j=0;j<NUM_THREADS;j++)
|
||||
printf("Passed argument %d for thread\n", i[j]);
|
||||
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t new_th;
|
||||
int i[NUM_THREADS], j;
|
||||
|
||||
for(j=0;j<NUM_THREADS;j++)
|
||||
i[j] = j+1;
|
||||
|
||||
if(pthread_create(&new_th, NULL, a_thread_func, (void*)&i) != 0)
|
||||
{
|
||||
printf("Error creating thread\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
/* Wait for thread to end execution */
|
||||
pthread_join(new_th, NULL);
|
||||
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
|
||||
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2002, Intel Corporation. All rights reserved.
|
||||
* Created by: rolla.n.selbak 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.
|
||||
|
||||
* Test pthread_create()
|
||||
*
|
||||
* The signal state of the new thread will be initialized as so:
|
||||
*
|
||||
* - The signal mask shall be inherited from the created thread
|
||||
* - The set of signals pending for the new thread shall be empty.
|
||||
*
|
||||
* Steps:
|
||||
* 1. In main(), create a signal mask with a few signals in the set (SIGUSR1 and SIGUSR2).
|
||||
* 2. Raise those signals in main. These signals now should be pending.
|
||||
* 3. Create a thread using pthread_create().
|
||||
* 4. The thread should have the same signal mask, but no signals should be pending.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include "posixtest.h"
|
||||
|
||||
sigset_t th_pendingset, th_sigmask;
|
||||
|
||||
void *a_thread_func()
|
||||
{
|
||||
/* Obtain the signal mask of this thread. */
|
||||
pthread_sigmask(SIG_SETMASK, NULL, &th_sigmask);
|
||||
|
||||
/* Obtain the pending signals of this thread. It should be empty. */
|
||||
if (sigpending(&th_pendingset) != 0) {
|
||||
printf("Error calling sigpending()\n");
|
||||
return (void *)PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t new_th;
|
||||
sigset_t main_sigmask, main_pendingset;
|
||||
int ret;
|
||||
|
||||
/* Empty set of signal mask and blocked signals */
|
||||
if ( (sigemptyset(&main_sigmask) != 0) ||
|
||||
(sigemptyset(&main_pendingset) != 0) )
|
||||
{
|
||||
perror("Error in sigemptyset()\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Add SIGCONT, SIGUSR1 and SIGUSR2 to the set of blocked signals */
|
||||
if (sigaddset(&main_sigmask, SIGUSR1) != 0)
|
||||
{
|
||||
perror("Error in sigaddset()\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
if (sigaddset(&main_sigmask, SIGUSR2) != 0)
|
||||
{
|
||||
perror("Error in sigaddset()\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Block those signals. */
|
||||
if (pthread_sigmask(SIG_SETMASK, &main_sigmask, NULL) != 0)
|
||||
{
|
||||
printf("Error in pthread_sigmask()\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Raise those signals so they are now pending. */
|
||||
if (raise(SIGUSR1) != 0) {
|
||||
printf("Could not raise SIGALRM\n");
|
||||
return -1;
|
||||
}
|
||||
if (raise(SIGUSR2) != 0) {
|
||||
printf("Could not raise SIGALRM\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a new thread. */
|
||||
if(pthread_create(&new_th, NULL, a_thread_func, NULL) != 0)
|
||||
{
|
||||
perror("Error creating thread\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Wait until the thread has finished execution. */
|
||||
if(pthread_join(new_th, NULL) != 0)
|
||||
{
|
||||
perror("Error in pthread_join()\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Check to make sure that the sigmask of the thread is the same as the main thread */
|
||||
ret = sigismember(&th_sigmask, SIGUSR1);
|
||||
if(ret != 1)
|
||||
{
|
||||
if(ret == 0)
|
||||
{
|
||||
printf("Error: Thread did not inherit main()s signal mask. SIGUSR1 not a member of the signal set.\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
perror("Error is sigismember()\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
ret = sigismember(&th_sigmask, SIGUSR2);
|
||||
if(ret != 1)
|
||||
{
|
||||
if(ret == 0)
|
||||
{
|
||||
printf("Test FAILED: Thread did not inherit main()s signal mask. SIGUSR2 not a member of the signal set.\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
perror("Error is sigismember()\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
/* Check to make sure that the pending set of the thread does not contain SIGUSR1 or
|
||||
* SIGUSR2. */
|
||||
|
||||
ret = sigismember(&th_pendingset, SIGUSR1);
|
||||
if(ret != 0)
|
||||
{
|
||||
if(ret == 1)
|
||||
{
|
||||
printf("Error: Thread did not inherit main()s signal mask. SIGUSR1 not a member of the signal set.\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
perror("Error is sigismember()\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
ret = sigismember(&th_pendingset, SIGUSR2);
|
||||
if(ret != 0)
|
||||
{
|
||||
if(ret == 1)
|
||||
{
|
||||
printf("Test FAILED: Thread did not inherit main()s signal mask. SIGUSR2 not a member of the signal set.\n");
|
||||
return PTS_FAIL;
|
||||
}
|
||||
|
||||
perror("Error is sigismember()\n");
|
||||
return PTS_UNRESOLVED;
|
||||
}
|
||||
|
||||
printf("Test PASSED\n");
|
||||
return PTS_PASS;
|
||||
}
|
||||
|
||||
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Bull S.A.. All rights reserved.
|
||||
* Created by: Sebastien Decugis
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it would be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
|
||||
|
||||
* This sample test aims to check the following assertion:
|
||||
*
|
||||
* The new thread inherits is signal mask from the calling thread,
|
||||
* and has no pending signal at creation time.
|
||||
|
||||
* The steps are:
|
||||
* 1. In main(), create a signal mask with a few signals in the set (SIGUSR1 and SIGUSR2).
|
||||
* 2. Raise those signals in main. These signals now should be pending.
|
||||
* 3. Create a thread using pthread_create().
|
||||
* 4. The thread should have the same signal mask, but no signals should be pending.
|
||||
|
||||
* Parts of this test are copied from 8-1.c (author: rolla.n.selbak REMOVE-THIS AT intel DOT com)
|
||||
*/
|
||||
|
||||
|
||||
/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
/* Some routines are part of the XSI Extensions */
|
||||
#ifndef WITHOUT_XOPEN
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
/********************************************************************************************/
|
||||
/****************************** standard includes *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sched.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
/****************************** Test framework *****************************************/
|
||||
/********************************************************************************************/
|
||||
#include "testfrmw.h"
|
||||
#include "testfrmw.c"
|
||||
/* This header is responsible for defining the following macros:
|
||||
* UNRESOLVED(ret, descr);
|
||||
* where descr is a description of the error and ret is an int (error code for example)
|
||||
* FAILED(descr);
|
||||
* where descr is a short text saying why the test has failed.
|
||||
* PASSED();
|
||||
* No parameter.
|
||||
*
|
||||
* Both three macros shall terminate the calling process.
|
||||
* The testcase shall not terminate in any other maneer.
|
||||
*
|
||||
* The other file defines the functions
|
||||
* void output_init()
|
||||
* void output(char * string, ...)
|
||||
*
|
||||
* Those may be used to output information.
|
||||
*/
|
||||
|
||||
/********************************************************************************************/
|
||||
/********************************** Configuration ******************************************/
|
||||
/********************************************************************************************/
|
||||
#ifndef VERBOSE
|
||||
#define VERBOSE 1
|
||||
#endif
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Test cases *****************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
#include "threads_scenarii.c"
|
||||
|
||||
/* This file will define the following objects:
|
||||
* scenarii: array of struct __scenario type.
|
||||
* NSCENAR : macro giving the total # of scenarii
|
||||
* scenar_init(): function to call before use the scenarii array.
|
||||
* scenar_fini(): function to call after end of use of the scenarii array.
|
||||
*/
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************** Real Test *****************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
sigset_t mask;
|
||||
sigset_t pending;
|
||||
} testdata_t;
|
||||
|
||||
|
||||
/* Thread function; which will check the signal mask and pending signals */
|
||||
void * threaded(void * arg)
|
||||
{
|
||||
int ret;
|
||||
testdata_t * td=(testdata_t *)arg;
|
||||
|
||||
/* Obtain the signal mask of this thread. */
|
||||
ret = pthread_sigmask(SIG_SETMASK, NULL, &(td->mask));
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to get the signal mask of the thread"); }
|
||||
|
||||
/* Obtain the pending signals of this thread. It should be empty. */
|
||||
ret = sigpending(&(td->pending));
|
||||
if (ret != 0) { UNRESOLVED(errno, "Failed to get pending signals from the thread"); }
|
||||
|
||||
/* Signal we're done (especially in case of a detached thread) */
|
||||
do { ret = sem_post(&scenarii[sc].sem); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); }
|
||||
|
||||
/* return */
|
||||
return arg;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int ret=0;
|
||||
pthread_t child;
|
||||
|
||||
testdata_t td_parent, td_thread;
|
||||
|
||||
/* Initialize output routine */
|
||||
output_init();
|
||||
|
||||
/* Initialize thread attribute objects */
|
||||
scenar_init();
|
||||
|
||||
/* Initialize the signal state */
|
||||
ret = sigemptyset(&(td_parent.mask));
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to initialize a signal set"); }
|
||||
|
||||
ret = sigemptyset(&(td_parent.pending));
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to initialize a signal set"); }
|
||||
|
||||
/* Add SIGCONT, SIGUSR1 and SIGUSR2 to the set of blocked signals */
|
||||
ret = sigaddset(&(td_parent.mask), SIGUSR1);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to add SIGUSR1 to the signal set"); }
|
||||
|
||||
ret = sigaddset(&(td_parent.mask), SIGUSR2);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to add SIGUSR2 to the signal set"); }
|
||||
|
||||
/* Block those signals. */
|
||||
ret = pthread_sigmask(SIG_SETMASK, &(td_parent.mask), NULL);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to mask the singals in main"); }
|
||||
|
||||
/* Raise those signals so they are now pending. */
|
||||
ret = raise(SIGUSR1);
|
||||
if (ret != 0) { UNRESOLVED(errno, "Failed to raise SIGUSR1"); }
|
||||
ret = raise(SIGUSR2);
|
||||
if (ret != 0) { UNRESOLVED(errno, "Failed to raise SIGUSR2"); }
|
||||
|
||||
/* Do the testing for each thread */
|
||||
for (sc=0; sc < NSCENAR; sc++)
|
||||
{
|
||||
#if VERBOSE > 0
|
||||
output("-----\n");
|
||||
output("Starting test with scenario (%i): %s\n", sc, scenarii[sc].descr);
|
||||
#endif
|
||||
|
||||
/* (re)initialize thread signal sets */
|
||||
ret = sigemptyset(&(td_thread.mask));
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to initialize a signal set"); }
|
||||
|
||||
ret = sigemptyset(&(td_thread.pending));
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to initialize a signal set"); }
|
||||
|
||||
|
||||
ret = pthread_create(&child, &scenarii[sc].ta, threaded, &td_thread);
|
||||
switch (scenarii[sc].result)
|
||||
{
|
||||
case 0: /* Operation was expected to succeed */
|
||||
if (ret != 0) { UNRESOLVED(ret, "Failed to create this thread"); }
|
||||
break;
|
||||
|
||||
case 1: /* Operation was expected to fail */
|
||||
if (ret == 0) { UNRESOLVED(-1, "An error was expected but the thread creation succeeded"); }
|
||||
break;
|
||||
|
||||
case 2: /* We did not know the expected result */
|
||||
default:
|
||||
#if VERBOSE > 0
|
||||
if (ret == 0)
|
||||
{ output("Thread has been created successfully for this scenario\n"); }
|
||||
else
|
||||
{ output("Thread creation failed with the error: %s\n", strerror(ret)); }
|
||||
#endif
|
||||
}
|
||||
if (ret == 0) /* The new thread is running */
|
||||
{
|
||||
if (scenarii[sc].detached == 0)
|
||||
{
|
||||
ret = pthread_join(child, NULL);
|
||||
if (ret != 0) { UNRESOLVED(ret, "Unable to join a thread"); }
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just wait for the thread to terminate */
|
||||
do { ret = sem_wait(&scenarii[sc].sem); }
|
||||
while ((ret == -1) && (errno == EINTR));
|
||||
if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); }
|
||||
}
|
||||
|
||||
/* The thread has terminated its work, so we can now control */
|
||||
ret = sigismember(&(td_thread.mask), SIGUSR1);
|
||||
if (ret != 1)
|
||||
{
|
||||
if (ret == 0) { FAILED("The thread did not inherit the signal mask"); }
|
||||
/* else */
|
||||
UNRESOLVED(ret, "sigismember() failed");
|
||||
}
|
||||
|
||||
ret = sigismember(&(td_thread.mask), SIGUSR2);
|
||||
if (ret != 1)
|
||||
{
|
||||
if (ret == 0) { FAILED("The thread did not inherit the signal mask"); }
|
||||
/* else */
|
||||
UNRESOLVED(ret, "sigismember() failed");
|
||||
}
|
||||
|
||||
ret = sigismember(&(td_thread.pending), SIGUSR1);
|
||||
if (ret != 0)
|
||||
{
|
||||
if (ret == 1) { FAILED("The thread inherited the pending signal SIGUSR1"); }
|
||||
/* else */
|
||||
UNRESOLVED(ret, "sigismember() failed");
|
||||
}
|
||||
|
||||
ret = sigismember(&(td_thread.pending), SIGUSR2);
|
||||
if (ret != 0)
|
||||
{
|
||||
if (ret == 1) { FAILED("The thread inherited the pending signal SIGUSR2"); }
|
||||
/* else */
|
||||
UNRESOLVED(ret, "sigismember() failed");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
scenar_fini();
|
||||
#if VERBOSE > 0
|
||||
output("-----\n");
|
||||
output("All test data destroyed\n");
|
||||
output("Test PASSED\n");
|
||||
#endif
|
||||
|
||||
PASSED;
|
||||
}
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
SubDir HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces pthread_create ;
|
||||
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) $(DOTDOT) include ] ;
|
||||
|
||||
SimpleTest pthread_create_1-1 : 1-1.c ;
|
||||
SimpleTest pthread_create_1-2 : 1-2.c ;
|
||||
SimpleTest pthread_create_1-3 : 1-3.c ;
|
||||
#SimpleTest pthread_create_1-4 : 1-4.c ;
|
||||
#SimpleTest pthread_create_1-5 : 1-5.c ;
|
||||
#SimpleTest pthread_create_1-6 : 1-6.c ;
|
||||
SimpleTest pthread_create_2-1 : 2-1.c ;
|
||||
SimpleTest pthread_create_3-1 : 3-1.c ;
|
||||
#SimpleTest pthread_create_3-2 : 3-2.c ;
|
||||
SimpleTest pthread_create_4-1 : 4-1.c ;
|
||||
SimpleTest pthread_create_5-1 : 5-1.c ;
|
||||
SimpleTest pthread_create_5-2 : 5-2.c ;
|
||||
SimpleTest pthread_create_8-1 : 8-1.c ;
|
||||
#SimpleTest pthread_create_8-2 : 8-2.c ;
|
||||
SimpleTest pthread_create_10-1 : 10-1.c ;
|
||||
#SimpleTest pthread_create_11-1 : 11-1.c ;
|
||||
SimpleTest pthread_create_12-1 : 12-1.c ;
|
||||
#SimpleTest pthread_create_14-1 : 14-1.c ;
|
||||
#SimpleTest pthread_create_15-1 : 15-1.c ;
|
||||
Reference in New Issue
Block a user