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
This commit is contained in:
@@ -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 ;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -11,5 +11,6 @@ MergeObject posix_pthread.o :
|
||||
pthread_key.c
|
||||
pthread_mutex.c
|
||||
pthread_mutexattr.c
|
||||
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 <pthread.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
+62
@@ -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 <pthread.h>
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
+118
@@ -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 <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.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 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;
|
||||
}
|
||||
|
||||
|
||||
+183
@@ -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 <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.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 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;
|
||||
}
|
||||
|
||||
|
||||
+118
@@ -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 <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.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 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;
|
||||
}
|
||||
|
||||
|
||||
+121
@@ -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 <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
+17
@@ -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.h>
|
||||
|
||||
pthread_once_t dummy = PTHREAD_ONCE_INIT;
|
||||
|
||||
|
||||
+365
@@ -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 <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <errno.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 *****************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
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;
|
||||
}
|
||||
+11
@@ -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 ;
|
||||
+70
@@ -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 <time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* 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
|
||||
+84
@@ -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 <string.h> /* 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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user