2006-05-24 18:19:34 +04:00
/*
Unix SMB / CIFS implementation .
testing of the events subsystem
2009-02-16 10:52:06 +03:00
Copyright ( C ) Stefan Metzmacher 2006 - 2009
* * NOTE ! The following LGPL license applies to the tevent
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 3 of the License , or ( at your option ) any later version .
This library is distributed in the hope that it will be useful ,
2006-05-24 18:19:34 +04:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2009-02-16 10:52:06 +03:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2006-05-24 18:19:34 +04:00
*/
# include "includes.h"
2012-07-30 11:00:13 +04:00
# include "lib/tevent/tevent.h"
2006-05-24 18:19:34 +04:00
# include "system/filesys.h"
2012-07-30 11:09:46 +04:00
# include "system/select.h"
2006-05-24 18:19:34 +04:00
# include "torture/torture.h"
2012-07-30 11:09:46 +04:00
# ifdef HAVE_PTHREAD
# include <pthread.h>
# include <assert.h>
# endif
2006-05-24 18:19:34 +04:00
static int fde_count ;
2008-12-29 22:24:57 +03:00
static void fde_handler ( struct tevent_context * ev_ctx , struct tevent_fd * f ,
2009-02-02 14:59:28 +03:00
uint16_t flags , void * private_data )
2006-05-24 18:19:34 +04:00
{
2009-02-02 14:59:28 +03:00
int * fd = ( int * ) private_data ;
2007-01-21 13:32:39 +03:00
char c ;
# ifdef SA_SIGINFO
kill ( getpid ( ) , SIGUSR1 ) ;
# endif
kill ( getpid ( ) , SIGALRM ) ;
read ( fd [ 0 ] , & c , 1 ) ;
write ( fd [ 1 ] , & c , 1 ) ;
2006-05-24 18:19:34 +04:00
fde_count + + ;
}
2008-12-29 22:24:57 +03:00
static void finished_handler ( struct tevent_context * ev_ctx , struct tevent_timer * te ,
2009-02-02 14:59:28 +03:00
struct timeval tval , void * private_data )
2006-05-24 18:19:34 +04:00
{
2009-02-02 14:59:28 +03:00
int * finished = ( int * ) private_data ;
2007-01-21 13:32:39 +03:00
( * finished ) = 1 ;
2006-05-24 18:19:34 +04:00
}
2012-05-14 13:48:00 +04:00
static void count_handler ( struct tevent_context * ev_ctx , struct tevent_signal * te ,
2009-02-02 14:59:28 +03:00
int signum , int count , void * info , void * private_data )
2007-01-21 13:32:39 +03:00
{
2009-02-02 14:59:28 +03:00
int * countp = ( int * ) private_data ;
2007-01-21 13:32:39 +03:00
( * countp ) + = count ;
}
static bool test_event_context ( struct torture_context * test ,
const void * test_data )
2006-05-24 18:19:34 +04:00
{
2008-12-29 22:24:57 +03:00
struct tevent_context * ev_ctx ;
2006-05-24 18:19:34 +04:00
int fd [ 2 ] = { - 1 , - 1 } ;
2007-01-05 12:35:49 +03:00
const char * backend = ( const char * ) test_data ;
2007-01-21 13:32:39 +03:00
int alarm_count = 0 , info_count = 0 ;
2008-12-29 22:24:57 +03:00
struct tevent_fd * fde ;
2009-07-16 11:06:42 +04:00
# ifdef SA_RESTART
struct tevent_signal * se1 = NULL ;
# endif
2013-02-23 00:48:11 +04:00
# ifdef SA_RESETHAND
2009-07-16 11:06:42 +04:00
struct tevent_signal * se2 = NULL ;
2013-02-23 00:48:11 +04:00
# endif
2009-07-16 11:06:42 +04:00
# ifdef SA_SIGINFO
struct tevent_signal * se3 = NULL ;
# endif
2007-01-21 13:32:39 +03:00
int finished = 0 ;
struct timeval t ;
char c = 0 ;
2012-05-14 13:48:00 +04:00
ev_ctx = tevent_context_init_byname ( test , backend ) ;
2007-01-05 12:35:49 +03:00
if ( ev_ctx = = NULL ) {
torture_comment ( test , " event backend '%s' not supported \n " , backend ) ;
return true ;
}
2013-02-23 00:48:11 +04:00
torture_comment ( test , " backend '%s' - %s \n " ,
backend , __FUNCTION__ ) ;
2007-01-05 12:35:49 +03:00
2006-05-24 18:19:34 +04:00
/* reset globals */
fde_count = 0 ;
/* create a pipe */
pipe ( fd ) ;
2012-05-14 13:48:00 +04:00
fde = tevent_add_fd ( ev_ctx , ev_ctx , fd [ 0 ] , TEVENT_FD_READ ,
fde_handler , fd ) ;
2009-01-03 14:39:11 +03:00
tevent_fd_set_auto_close ( fde ) ;
2007-01-21 13:32:39 +03:00
2012-05-14 13:48:00 +04:00
tevent_add_timer ( ev_ctx , ev_ctx , timeval_current_ofs ( 2 , 0 ) ,
finished_handler , & finished ) ;
2006-05-24 18:19:34 +04:00
2009-07-16 11:06:42 +04:00
# ifdef SA_RESTART
2012-05-14 13:48:00 +04:00
se1 = tevent_add_signal ( ev_ctx , ev_ctx , SIGALRM , SA_RESTART , count_handler , & alarm_count ) ;
2013-02-23 00:48:11 +04:00
torture_assert ( test , se1 ! = NULL , " failed to setup se1 " ) ;
2009-07-16 11:06:42 +04:00
# endif
2011-08-01 22:49:10 +04:00
# ifdef SA_RESETHAND
2012-05-14 13:48:00 +04:00
se2 = tevent_add_signal ( ev_ctx , ev_ctx , SIGALRM , SA_RESETHAND , count_handler , & alarm_count ) ;
2013-02-23 00:48:11 +04:00
torture_assert ( test , se2 ! = NULL , " failed to setup se2 " ) ;
2011-08-01 22:49:10 +04:00
# endif
2007-01-21 13:32:39 +03:00
# ifdef SA_SIGINFO
2012-05-14 13:48:00 +04:00
se3 = tevent_add_signal ( ev_ctx , ev_ctx , SIGUSR1 , SA_SIGINFO , count_handler , & info_count ) ;
2013-02-23 00:48:11 +04:00
torture_assert ( test , se3 ! = NULL , " failed to setup se3 " ) ;
2007-01-21 13:32:39 +03:00
# endif
2006-05-24 18:19:34 +04:00
2007-01-21 13:32:39 +03:00
write ( fd [ 1 ] , & c , 1 ) ;
t = timeval_current ( ) ;
while ( ! finished ) {
2007-08-10 11:40:50 +04:00
errno = 0 ;
2012-05-14 13:48:00 +04:00
if ( tevent_loop_once ( ev_ctx ) = = - 1 ) {
2007-01-24 07:30:44 +03:00
talloc_free ( ev_ctx ) ;
2007-08-17 09:21:05 +04:00
torture_fail ( test , talloc_asprintf ( test , " Failed event loop %s \n " , strerror ( errno ) ) ) ;
2007-01-24 07:30:44 +03:00
}
2007-01-21 13:32:39 +03:00
}
talloc_free ( fde ) ;
close ( fd [ 1 ] ) ;
while ( alarm_count < fde_count + 1 ) {
2012-05-14 13:48:00 +04:00
if ( tevent_loop_once ( ev_ctx ) = = - 1 ) {
2007-01-24 07:30:44 +03:00
break ;
}
2007-01-21 13:32:39 +03:00
}
torture_comment ( test , " Got %.2f pipe events/sec \n " , fde_count / timeval_elapsed ( & t ) ) ;
2009-07-16 11:06:42 +04:00
# ifdef SA_RESTART
2007-01-21 13:32:39 +03:00
talloc_free ( se1 ) ;
2009-07-16 11:06:42 +04:00
# endif
2007-01-21 13:32:39 +03:00
torture_assert_int_equal ( test , alarm_count , 1 + fde_count , " alarm count mismatch " ) ;
2013-02-23 00:48:11 +04:00
# ifdef SA_RESETHAND
/*
* we do not call talloc_free ( se2 )
* because it is already gone ,
* after triggering the event handler .
*/
# endif
2007-01-21 13:32:39 +03:00
# ifdef SA_SIGINFO
talloc_free ( se3 ) ;
torture_assert_int_equal ( test , info_count , fde_count , " info count mismatch " ) ;
# endif
2006-05-24 18:19:34 +04:00
2006-06-17 02:06:09 +04:00
talloc_free ( ev_ctx ) ;
2007-01-21 13:32:39 +03:00
2006-10-16 17:06:41 +04:00
return true ;
2006-05-24 18:19:34 +04:00
}
2012-07-30 11:09:46 +04:00
# ifdef HAVE_PTHREAD
static pthread_mutex_t threaded_mutex = PTHREAD_MUTEX_INITIALIZER ;
static bool do_shutdown = false ;
static void test_event_threaded_lock ( void )
{
int ret ;
ret = pthread_mutex_lock ( & threaded_mutex ) ;
assert ( ret = = 0 ) ;
}
static void test_event_threaded_unlock ( void )
{
int ret ;
ret = pthread_mutex_unlock ( & threaded_mutex ) ;
assert ( ret = = 0 ) ;
}
static void test_event_threaded_trace ( enum tevent_trace_point point ,
void * private_data )
{
switch ( point ) {
case TEVENT_TRACE_BEFORE_WAIT :
test_event_threaded_unlock ( ) ;
break ;
case TEVENT_TRACE_AFTER_WAIT :
test_event_threaded_lock ( ) ;
break ;
2013-02-26 18:54:57 +04:00
case TEVENT_TRACE_BEFORE_LOOP_ONCE :
case TEVENT_TRACE_AFTER_LOOP_ONCE :
break ;
2012-07-30 11:09:46 +04:00
}
}
static void test_event_threaded_timer ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval current_time ,
void * private_data )
{
return ;
}
static void * test_event_poll_thread ( void * private_data )
{
struct tevent_context * ev = ( struct tevent_context * ) private_data ;
test_event_threaded_lock ( ) ;
while ( true ) {
int ret ;
ret = tevent_loop_once ( ev ) ;
assert ( ret = = 0 ) ;
if ( do_shutdown ) {
test_event_threaded_unlock ( ) ;
return NULL ;
}
}
}
static void test_event_threaded_read_handler ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags ,
void * private_data )
{
int * pfd = ( int * ) private_data ;
char c ;
ssize_t nread ;
if ( ( flags & TEVENT_FD_READ ) = = 0 ) {
return ;
}
do {
nread = read ( * pfd , & c , 1 ) ;
} while ( ( nread = = - 1 ) & & ( errno = = EINTR ) ) ;
assert ( nread = = 1 ) ;
}
static bool test_event_context_threaded ( struct torture_context * test ,
const void * test_data )
{
struct tevent_context * ev ;
struct tevent_timer * te ;
struct tevent_fd * fde ;
pthread_t poll_thread ;
int fds [ 2 ] ;
int ret ;
char c = 0 ;
ev = tevent_context_init_byname ( test , " poll_mt " ) ;
torture_assert ( test , ev ! = NULL , " poll_mt not supported " ) ;
tevent_set_trace_callback ( ev , test_event_threaded_trace , NULL ) ;
te = tevent_add_timer ( ev , ev , timeval_current_ofs ( 5 , 0 ) ,
test_event_threaded_timer , NULL ) ;
torture_assert ( test , te ! = NULL , " Could not add timer " ) ;
ret = pthread_create ( & poll_thread , NULL , test_event_poll_thread , ev ) ;
torture_assert ( test , ret = = 0 , " Could not create poll thread " ) ;
ret = pipe ( fds ) ;
torture_assert ( test , ret = = 0 , " Could not create pipe " ) ;
poll ( NULL , 0 , 100 ) ;
test_event_threaded_lock ( ) ;
fde = tevent_add_fd ( ev , ev , fds [ 0 ] , TEVENT_FD_READ ,
test_event_threaded_read_handler , & fds [ 0 ] ) ;
torture_assert ( test , fde ! = NULL , " Could not add fd event " ) ;
test_event_threaded_unlock ( ) ;
poll ( NULL , 0 , 100 ) ;
write ( fds [ 1 ] , & c , 1 ) ;
poll ( NULL , 0 , 100 ) ;
test_event_threaded_lock ( ) ;
do_shutdown = true ;
test_event_threaded_unlock ( ) ;
write ( fds [ 1 ] , & c , 1 ) ;
ret = pthread_join ( poll_thread , NULL ) ;
torture_assert ( test , ret = = 0 , " pthread_join failed " ) ;
return true ;
}
# endif
2006-06-17 04:17:50 +04:00
struct torture_suite * torture_local_event ( TALLOC_CTX * mem_ctx )
2006-05-24 18:19:34 +04:00
{
2010-12-11 05:26:31 +03:00
struct torture_suite * suite = torture_suite_create ( mem_ctx , " event " ) ;
2012-05-14 13:48:00 +04:00
const char * * list = tevent_backend_list ( suite ) ;
2007-01-05 12:35:49 +03:00
int i ;
2006-05-24 18:19:34 +04:00
2007-01-05 12:35:49 +03:00
for ( i = 0 ; list & & list [ i ] ; i + + ) {
2007-12-24 22:04:56 +03:00
torture_suite_add_simple_tcase_const ( suite , list [ i ] ,
2007-01-05 12:35:49 +03:00
test_event_context ,
( const void * ) list [ i ] ) ;
}
2006-05-24 18:19:34 +04:00
2012-07-30 11:09:46 +04:00
# ifdef HAVE_PTHREAD
torture_suite_add_simple_tcase_const ( suite , " poll_mt_threaded " ,
test_event_context_threaded ,
NULL ) ;
# endif
2006-06-17 04:17:50 +04:00
return suite ;
2006-05-24 18:19:34 +04:00
}