From d2d6724788673441c7a06373ce434ee9c8059a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Fri, 7 Dec 2007 21:02:59 +0000 Subject: [PATCH] added pthread_once() implementation and tests there is still a TODO on an init race condition git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23076 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- build/jam/HaikuImage | 2 + headers/posix/pthread.h | 1 + src/system/libroot/posix/pthread/Jamfile | 1 + .../libroot/posix/pthread/pthread_once.c | 31 ++ .../conformance/interfaces/Jamfile | 1 + .../conformance/interfaces/pthread_once/1-1.c | 62 +++ .../conformance/interfaces/pthread_once/1-2.c | 118 ++++++ .../conformance/interfaces/pthread_once/1-3.c | 183 +++++++++ .../conformance/interfaces/pthread_once/2-1.c | 118 ++++++ .../conformance/interfaces/pthread_once/3-1.c | 121 ++++++ .../conformance/interfaces/pthread_once/4-1.c | 17 + .../conformance/interfaces/pthread_once/6-1.c | 365 ++++++++++++++++++ .../interfaces/pthread_once/Jamfile | 11 + .../interfaces/pthread_once/testfrmw.c | 70 ++++ .../interfaces/pthread_once/testfrmw.h | 84 ++++ .../posix/posixtestsuite/run_posix_tests.sh | 8 +- 16 files changed, 1192 insertions(+), 1 deletion(-) create mode 100644 src/system/libroot/posix/pthread/pthread_once.c create mode 100644 src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/1-1.c create mode 100644 src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/1-2.c create mode 100644 src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/1-3.c create mode 100644 src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/2-1.c create mode 100644 src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/3-1.c create mode 100644 src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/4-1.c create mode 100644 src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/6-1.c create mode 100644 src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/Jamfile create mode 100644 src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/testfrmw.c create mode 100644 src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/testfrmw.h diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 48de00f2c1..8403ece5c1 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -456,6 +456,8 @@ if $(HAIKU_ADD_POSIX_TEST_SUITE_TO_IMAGE) { pthread_key_create_3-1 ; AddFilesToHaikuImage home posixtestsuite conformance interfaces pthread_key_delete : pthread_key_delete_1-1 pthread_key_delete_1-2 pthread_key_delete_2-1 ; + AddFilesToHaikuImage home posixtestsuite conformance interfaces pthread_once + : pthread_once_1-1 pthread_once_1-2 pthread_once_1-3 pthread_once_2-1 ; AddFilesToHaikuImage home posixtestsuite conformance interfaces pthread_setspecific : pthread_setspecific_1-1 pthread_setspecific_1-2 ; } diff --git a/headers/posix/pthread.h b/headers/posix/pthread.h index 5d976a911f..9f84d3255e 100644 --- a/headers/posix/pthread.h +++ b/headers/posix/pthread.h @@ -125,6 +125,7 @@ extern int pthread_condattr_setpshared(pthread_condattr_t *condAttr, int process /* misc. functions */ extern int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)); +extern int pthread_once(pthread_once_t *once_control, void (*init_routine)()); /* thread attributes functions */ extern int pthread_attr_destroy(pthread_attr_t *attr); diff --git a/src/system/libroot/posix/pthread/Jamfile b/src/system/libroot/posix/pthread/Jamfile index a680515df1..fd8261fc27 100644 --- a/src/system/libroot/posix/pthread/Jamfile +++ b/src/system/libroot/posix/pthread/Jamfile @@ -11,5 +11,6 @@ MergeObject posix_pthread.o : pthread_key.c pthread_mutex.c pthread_mutexattr.c + pthread_once.c ; diff --git a/src/system/libroot/posix/pthread/pthread_once.c b/src/system/libroot/posix/pthread/pthread_once.c new file mode 100644 index 0000000000..d77a1adbb7 --- /dev/null +++ b/src/system/libroot/posix/pthread/pthread_once.c @@ -0,0 +1,31 @@ +/* +** Copyright 2007, Jérôme Duval. All rights reserved. +** Distributed under the terms of the MIT License. +*/ + + +#include +#include "pthread_private.h" + + +int +pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) +{ + if (once_control->state == PTHREAD_NEEDS_INIT) { + // TODO race condition ? + if (once_control->mutex == NULL) { + if (pthread_mutex_init(&once_control->mutex, NULL) != 0) + return -1; + } + pthread_mutex_lock(&once_control->mutex); + + if (once_control->state == PTHREAD_NEEDS_INIT) { + init_routine(); + once_control->state = PTHREAD_DONE_INIT; + } + + pthread_mutex_unlock(&once_control->mutex); + } + return 0; +} + diff --git a/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/Jamfile b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/Jamfile index b6709bb51d..052d8e9006 100644 --- a/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/Jamfile +++ b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/Jamfile @@ -6,6 +6,7 @@ SubInclude HAIKU_TOP src tests system libroot posix posixtestsuite conformance i 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 ; diff --git a/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/1-1.c b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/1-1.c new file mode 100644 index 0000000000..6771c7be2f --- /dev/null +++ b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/1-1.c @@ -0,0 +1,62 @@ +/* + * 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_once() + * + * Dynamic package installation. Tihe first call to pthread_once() by any + * thread in a process, with a given 'once_control', shall call the + * 'init_routine' with no arguments. Subsequent calls of pthread_once() + * with the same once_control shall not call the 'init_routine'. The + * 'once_control' paramter shall determine whether the associated + * initialization routine has been called. + * + * STEPS: + * 1.Initialize a pthread_once object + * 2.Call pthread_once passing it this object + * 3.Call pthread_once again, this time, it shouldn't execute the function + * passed to it. If it does, the test fails. + */ + +#include +#include +#include "posixtest.h" + +/* Keeps track of how many times the init function has been called. */ +int init_flag; + +/* The init function that pthread_once calls */ +void *an_init_func() +{ + init_flag++; + return NULL; +} + +int main() +{ + pthread_once_t once_control = PTHREAD_ONCE_INIT; + + init_flag=0; + + /* Call pthread_once, passing it the once_control */ + pthread_once(&once_control, (void*)an_init_func); + + /* Call pthread_once again. The init function should not be + * called. */ + pthread_once(&once_control, (void*)an_init_func); + + if(init_flag != 1) + { + printf("Test FAILED\n"); + return PTS_FAIL; + } + + printf("Test PASSED\n"); + return PTS_PASS; + +} + + diff --git a/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/1-2.c b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/1-2.c new file mode 100644 index 0000000000..c29175b047 --- /dev/null +++ b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/1-2.c @@ -0,0 +1,118 @@ +/* +* 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: +* +* In a process, the first call to pthread_once with a given once_control +* calls the init routine. + +* The steps are: +* -> call pthread_once +* -> check the init_routine executed + +* The test fails if the init_routine has not been called after pthread_once +* has returned. + +*/ + + +/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ +#define _POSIX_C_SOURCE 200112L + +/********************************************************************************************/ +/****************************** standard includes *****************************************/ +/********************************************************************************************/ +#include +#include +#include +#include +#include +#include + +/********************************************************************************************/ +/****************************** 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 case *****************************************/ +/********************************************************************************************/ + +int control; + +void my_init( void ) +{ + + control = 1; + + return ; +} + +/* The main test function. */ +int main( int argc, char * argv[] ) +{ + int ret; + + pthread_once_t myctl = PTHREAD_ONCE_INIT; + + /* Initialize output */ + output_init(); + + control = 0; + + /* Call the initializer */ + ret = pthread_once( &myctl, my_init ); + + if ( ret != 0 ) + { + UNRESOLVED( ret, "pthread_once failed" ); + } + + if ( control != 1 ) + { + FAILED( "The initializer function did not execute" ); + } + + PASSED; +} + + diff --git a/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/1-3.c b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/1-3.c new file mode 100644 index 0000000000..fbe2b0f173 --- /dev/null +++ b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/1-3.c @@ -0,0 +1,183 @@ +/* +* 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: +* +* Subsequent calls with the same once_control do not call init routine. + +* The steps are: +* -> Create several threads +* -> each call pthread_once +* -> check the init_routine executed once + +* The test fails if the init_routine has not been called or has +* been called several times. + +*/ + + +/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ +#define _POSIX_C_SOURCE 200112L + +/********************************************************************************************/ +/****************************** standard includes *****************************************/ +/********************************************************************************************/ +#include +#include +#include +#include +#include +#include + +/********************************************************************************************/ +/****************************** 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 NTHREADS 30 + +/********************************************************************************************/ +/*********************************** Test case *****************************************/ +/********************************************************************************************/ + +int control; +pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; + +void my_init( void ) +{ + int ret = 0; + ret = pthread_mutex_lock( &mtx ); + + if ( ret != 0 ) + { + UNRESOLVED( ret, "Failed to lock mutex in initializer" ); + } + + control++; + + ret = pthread_mutex_unlock( &mtx ); + + if ( ret != 0 ) + { + UNRESOLVED( ret, "Failed to unlock mutex in initializer" ); + } + + return ; +} + +/* Thread function */ +void * threaded ( void * arg ) +{ + int ret; + + ret = pthread_once( arg, my_init ); + + if ( ret != 0 ) + { + UNRESOLVED( ret, "pthread_once failed" ); + } + + return NULL; +} + +/* The main test function. */ +int main( int argc, char * argv[] ) +{ + int ret, i; + + pthread_once_t myctl = PTHREAD_ONCE_INIT; + + pthread_t th[ NTHREADS ]; + + /* Initialize output */ + output_init(); + + control = 0; + + /* Create the children */ + + for ( i = 0; i < NTHREADS; i++ ) + { + ret = pthread_create( &th[ i ], NULL, threaded, &myctl ); + + if ( ret != 0 ) + { + UNRESOLVED( ret, "Failed to create a thread" ); + } + } + + /* Then join */ + for ( i = 0; i < NTHREADS; i++ ) + { + ret = pthread_join( th[ i ], NULL ); + + if ( ret != 0 ) + { + UNRESOLVED( ret, "Failed to join a thread" ); + } + } + + /* Fetch the memory */ + ret = pthread_mutex_lock( &mtx ); + + if ( ret != 0 ) + { + UNRESOLVED( ret, "Failed to lock mutex in initializer" ); + } + + if ( control != 1 ) + { + output( "Control: %d\n", control ); + FAILED( "The initializer function did not execute once" ); + } + + ret = pthread_mutex_unlock( &mtx ); + + if ( ret != 0 ) + { + UNRESOLVED( ret, "Failed to unlock mutex in initializer" ); + } + + PASSED; +} + + diff --git a/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/2-1.c b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/2-1.c new file mode 100644 index 0000000000..b50cc1c82d --- /dev/null +++ b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/2-1.c @@ -0,0 +1,118 @@ +/* +* 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_once returns only when init routine has completed. + +* The steps are: +* -> call pthread_once (the init routine lasts for 1 second) +* -> check the init_routine executed + +* The test fails if the init_routine has not been completed when pthread_once +* returns. + +*/ + + +/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ +#define _POSIX_C_SOURCE 200112L + +/********************************************************************************************/ +/****************************** standard includes *****************************************/ +/********************************************************************************************/ +#include +#include +#include +#include +#include +#include + +/********************************************************************************************/ +/****************************** 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 case *****************************************/ +/********************************************************************************************/ + +int control; + +void my_init( void ) +{ + sleep( 1 ); + + control = 1; + + return ; +} + +/* The main test function. */ +int main( int argc, char * argv[] ) +{ + int ret; + + pthread_once_t myctl = PTHREAD_ONCE_INIT; + + /* Initialize output */ + output_init(); + + control = 0; + + /* Call the initializer */ + ret = pthread_once( &myctl, my_init ); + + if ( ret != 0 ) + { + UNRESOLVED( ret, "pthread_once failed" ); + } + + if ( control != 1 ) + { + FAILED( "The initializer function did not execute" ); + } + + PASSED; +} + + diff --git a/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/3-1.c b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/3-1.c new file mode 100644 index 0000000000..f1ceb9e19f --- /dev/null +++ b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/3-1.c @@ -0,0 +1,121 @@ +/* + * 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_once() + * + * The pthread_once() function is not a cancelation point. However if + * 'init_routine'is a cancelation point and is canceled, the effect on + * 'once_control' shall be as if pthread_once() was never called. + * + * STEPS: + * 1. Create a cancelable thread. + * 2. In the thread routine, call pthread_once using a global pthread_once_t + * object. + * 3. Cancel the thread during the pthread_once init function + * 4. Call pthread_once again with the same pthread once_t object + * 5. This should call the pthread_once init function. If not, the test fails. + */ + +#include +#include +#include +#include "posixtest.h" + +/* Global pthread_once_t object */ +pthread_once_t once_control; + +/* Keeps track of how many times the init function has been called. */ +int init_flag; + +/* The init function that pthread_once calls */ +void *an_init_func() +{ + /* Indicate to main() that the init function has been reached */ + init_flag=1; + + /* Stay in a continuous loop until the thread that called + * this function gets canceled */ + sleep(10); + + /* The thread could not be canceled, timeout after 10 secs */ + perror("Init function timed out (10 secs), thread could not be canceled\n"); + init_flag=-1; + return NULL; +} + +/* Thread function */ +void *a_thread_func() +{ + /* Make the thread cancelable immediately */ + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + pthread_once(&once_control, (void*)an_init_func); + return NULL; +} + +/* 2nd init function used by the 2nd call of pthread_once */ +void *an_init_func2() +{ + /* Indicate to main() that this init function has been reached */ + init_flag=1; + return NULL; +} + +int main() +{ + pthread_t new_th; + once_control = PTHREAD_ONCE_INIT; + init_flag=0; + + /* Create a thread that will execute the first call to pthread_once() */ + if(pthread_create(&new_th, NULL, a_thread_func, NULL) != 0) + { + perror("Error creating thread\n"); + return PTS_UNRESOLVED; + } + + /* Wait until the init function is reached to cancel the thread */ + while(init_flag==0) + sleep(1); + + /* Send cancel request to the thread*/ + if(pthread_cancel(new_th) != 0) + { + perror("Could send cancel request to thread\n"); + return PTS_UNRESOLVED; + } + + /* Wait until the thread is canceled */ + pthread_join(new_th, NULL); + + /* If the thread could not be canceled and timed out, send + * an error */ + if (init_flag == -1) + { + perror("Error: could not cancel thread\n"); + return PTS_UNRESOLVED; + } + + init_flag=0; + + /* Should be able to call pthread_once() again with the same + * pthread_once_t object. */ + pthread_once(&once_control, (void*)an_init_func2); + + /* If the init function from the 2nd call to pthread_once() was not + * reached, the test fails. */ + if(init_flag != 1) + { + printf("Test FAILED\n: %d", init_flag); + return PTS_FAIL; + } + + printf("Test PASSED\n"); + return PTS_PASS; +} + + diff --git a/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/4-1.c b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/4-1.c new file mode 100644 index 0000000000..45b72f2087 --- /dev/null +++ b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/4-1.c @@ -0,0 +1,17 @@ + /* + * 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_once() + + *The constant PTHREAD_ONCE_INIT is defined in the pthread.h header. + */ + +#include + +pthread_once_t dummy = PTHREAD_ONCE_INIT; + + diff --git a/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/6-1.c b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/6-1.c new file mode 100644 index 0000000000..221ba6a665 --- /dev/null +++ b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/6-1.c @@ -0,0 +1,365 @@ +/* +* 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: +* -> kill a thread which calls pthread_once +* -> check that EINTR is never returned + +*/ + + +/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ +#define _POSIX_C_SOURCE 200112L + +/********************************************************************************************/ +/****************************** standard includes *****************************************/ +/********************************************************************************************/ +#include + #include + #include + #include + #include + #include + +#include + #include + #include + +/********************************************************************************************/ +/****************************** 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 *****************************************/ +/********************************************************************************************/ + +char do_it = 1; +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 +} + +int init_ctl; +/* Init function */ +void initializer( void ) +{ + init_ctl++; + return ; +} + + +/* Test function -- calls pthread_equal() and checks that EINTR is never returned. */ +void * test( void * arg ) +{ + int ret = 0; + pthread_once_t once_ctl; + + /* 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" ); + } + + + while ( do_it ) + { + count_ope++; + + once_ctl = PTHREAD_ONCE_INIT; + init_ctl = 0; + + ret = pthread_once( &once_ctl, initializer ); + + if ( ret == EINTR ) + { + FAILED( "pthread_once returned EINTR" ); + } + + if ( ret != 0 ) + { + UNRESOLVED( ret, "pthread_once failed" ); + } + + ret = pthread_once( &once_ctl, initializer ); + + if ( ret == EINTR ) + { + FAILED( "pthread_once returned EINTR" ); + } + + if ( ret != 0 ) + { + UNRESOLVED( ret, "pthread_once failed" ); + } + + if ( init_ctl != 1 ) + { + output( "init_ctl:%d\n", init_ctl ); + FAILED( "The initializer did not execute as expected" ); + } + + } + + 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(); + + /* 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" ); + } + + +#if VERBOSE > 0 + output( "Test executed successfully.\n" ); + + output( " %d initializations.\n", count_ope ); + +#ifdef WITH_SYNCHRO + output( " %d signals were sent meanwhile.\n", count_sig ); + +#endif + #endif + PASSED; +} diff --git a/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/Jamfile b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/Jamfile new file mode 100644 index 0000000000..6f93cbba79 --- /dev/null +++ b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/Jamfile @@ -0,0 +1,11 @@ +SubDir HAIKU_TOP src tests system libroot posix posixtestsuite conformance interfaces pthread_once ; + +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) $(DOTDOT) include ] ; + +SimpleTest pthread_once_1-1 : 1-1.c ; +SimpleTest pthread_once_1-2 : 1-2.c ; +SimpleTest pthread_once_1-3 : 1-3.c ; +SimpleTest pthread_once_2-1 : 2-1.c ; +#SimpleTest pthread_once_3-1 : 3-1.c ; +#SimpleTest pthread_once_4-1 : 4-1.c ; +#SimpleTest pthread_once_6-1 : 6-1.c ; diff --git a/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/testfrmw.c b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/testfrmw.c new file mode 100644 index 0000000000..b313cfd260 --- /dev/null +++ b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/testfrmw.c @@ -0,0 +1,70 @@ +/* + * 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 file is a wrapper to use the tests from the NPTL Test & Trace Project + * with either the Linux Test Project or the Open POSIX Test Suite. + + * The following function are defined: + * void output_init() + * void output_fini() + * void output(char * string, ...) + * + * The are used to output informative text (as a printf). + */ + +#include +#include + +/* We use a mutex to avoid conflicts in traces */ +static pthread_mutex_t m_trace = PTHREAD_MUTEX_INITIALIZER; + +/*****************************************************************************************/ +/******************************* stdout module *****************************************/ +/*****************************************************************************************/ +/* The following functions will output to stdout */ +#if (1) +static void output_init() +{ + /* do nothing */ + return; +} +static void output( char * string, ... ) +{ + va_list ap; + char *ts="[??:??:??]"; + struct tm * now; + time_t nw; + + pthread_mutex_lock(&m_trace); + nw = time(NULL); + now = localtime(&nw); + if (now == NULL) + printf(ts); + else + printf("[%2.2d:%2.2d:%2.2d]", now->tm_hour, now->tm_min, now->tm_sec); + va_start( ap, string); + vprintf(string, ap); + va_end(ap); + pthread_mutex_unlock(&m_trace); +} +static void output_fini() +{ + /*do nothing */ + return; +} +#endif diff --git a/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/testfrmw.h b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/testfrmw.h new file mode 100644 index 0000000000..96543ac39e --- /dev/null +++ b/src/tests/system/libroot/posix/posixtestsuite/conformance/interfaces/pthread_once/testfrmw.h @@ -0,0 +1,84 @@ +/* + * 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 file is a wrapper to use the tests from the NPTL Test & Trace Project + * with either the Linux Test Project or the Open POSIX Test Suite. + + * The following macros are defined here: + * 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 without calling one of those macros. + * + * + */ + +#include "posixtest.h" +#include /* for the strerror() routine */ + + +#ifdef __GNUC__ /* We are using GCC */ + + #define UNRESOLVED(x, s) \ + { output("Test %s unresolved: got %i (%s) on line %i (%s)\n", __FILE__, x, strerror(x), __LINE__, s); \ + output_fini(); \ + exit(PTS_UNRESOLVED); } + + #define FAILED(s) \ + { output("Test %s FAILED: %s\n", __FILE__, s); \ + output_fini(); \ + exit(PTS_FAIL); } + + #define PASSED \ + output_fini(); \ + exit(PTS_PASS); + + #define UNTESTED(s) \ +{ output("File %s cannot test: %s\n", __FILE__, s); \ + output_fini(); \ + exit(PTS_UNTESTED); \ +} + +#else /* not using GCC */ + + #define UNRESOLVED(x, s) \ + { output("Test unresolved: got %i (%s) on line %i (%s)\n", x, strerror(x), __LINE__, s); \ + output_fini(); \ + exit(PTS_UNRESOLVED); } + + #define FAILED(s) \ + { output("Test FAILED: %s\n", s); \ + output_fini(); \ + exit(PTS_FAIL); } + + #define PASSED \ + output_fini(); \ + exit(PTS_PASS); + + #define UNTESTED(s) \ +{ output("Unable to test: %s\n", s); \ + output_fini(); \ + exit(PTS_UNTESTED); \ +} + +#endif diff --git a/src/tests/system/libroot/posix/posixtestsuite/run_posix_tests.sh b/src/tests/system/libroot/posix/posixtestsuite/run_posix_tests.sh index 44352ed617..d61b95c8a8 100644 --- a/src/tests/system/libroot/posix/posixtestsuite/run_posix_tests.sh +++ b/src/tests/system/libroot/posix/posixtestsuite/run_posix_tests.sh @@ -64,7 +64,13 @@ threads_tests() conformance/interfaces/pthread_key_delete/pthread_key_delete_1-2 # conformance/interfaces/pthread_key_delete/pthread_key_delete_2-1 echo "pthread_key_delete_2-1: FIXME: test blocks, see bug #1642" - echo "" + echo + echo "pthread_once()" + conformance/interfaces/pthread_once/pthread_once_1-1 + conformance/interfaces/pthread_once/pthread_once_1-2 + conformance/interfaces/pthread_once/pthread_once_1-3 + conformance/interfaces/pthread_once/pthread_once_2-1 + echo echo "pthread_setspecific()" conformance/interfaces/pthread_setspecific/pthread_setspecific_1-1 conformance/interfaces/pthread_setspecific/pthread_setspecific_1-2