2009-04-09 02:46:49 +04:00
/*
Unix SMB / CIFS implementation .
SMB client library implementation ( thread interface functions ) .
Copyright ( C ) Jeremy Allison , 2009.
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
/*
* This code is based in the ideas in openssl
* but somewhat simpler and expended to include
* thread local storage .
*/
# include "includes.h"
2009-04-28 17:33:21 +04:00
# include "smb_threads.h"
2009-04-09 02:46:49 +04:00
/*********************************************************
Functions to vector the locking primitives used internally
by libsmbclient .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
const struct smb_thread_functions * global_tfp ;
/*********************************************************
Dynamic lock array .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void * * global_lock_array ;
2009-05-11 05:55:23 +04:00
/*********************************************************
Mutex used for our internal " once " function
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-05-13 22:31:40 +04:00
static void * once_mutex = NULL ;
2009-05-11 05:55:23 +04:00
2009-04-09 02:46:49 +04:00
/*********************************************************
Function to set the locking primitives used by libsmbclient .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int smb_thread_set_functions ( const struct smb_thread_functions * tf )
{
int i ;
global_tfp = tf ;
2009-04-14 23:23:22 +04:00
# if defined(PARANOID_MALLOC_CHECKER)
# ifdef malloc
# undef malloc
# endif
# endif
2009-04-09 02:46:49 +04:00
/* Here we initialize any static locks we're using. */
2009-04-14 23:23:22 +04:00
global_lock_array = ( void * * ) malloc ( sizeof ( void * ) * NUM_GLOBAL_LOCKS ) ;
# if defined(PARANOID_MALLOC_CHECKER)
# define malloc(s) __ERROR_DONT_USE_MALLOC_DIRECTLY
# endif
2009-04-09 02:46:49 +04:00
if ( global_lock_array = = NULL ) {
return ENOMEM ;
}
for ( i = 0 ; i < NUM_GLOBAL_LOCKS ; i + + ) {
char * name = NULL ;
if ( asprintf ( & name , " global_lock_%d " , i ) = = - 1 ) {
SAFE_FREE ( global_lock_array ) ;
return ENOMEM ;
}
2009-04-14 23:23:22 +04:00
if ( global_tfp - > create_mutex ( name ,
2009-04-09 02:46:49 +04:00
& global_lock_array [ i ] ,
2009-04-14 23:23:22 +04:00
__location__ ) ) {
smb_panic ( " smb_thread_set_functions: create mutexes failed " ) ;
}
2009-04-09 02:46:49 +04:00
SAFE_FREE ( name ) ;
}
2009-05-11 05:55:23 +04:00
/* Create the mutex we'll use for our "once" function */
if ( SMB_THREAD_CREATE_MUTEX ( " smb_once " , once_mutex ) ! = 0 ) {
smb_panic ( " smb_thread_set_functions: failed to create 'once' mutex " ) ;
}
2009-04-09 02:46:49 +04:00
return 0 ;
}
2009-05-11 05:55:23 +04:00
/*******************************************************************
Call a function only once . We implement this ourselves
using our own mutex rather than using the thread implementation ' s
* _once ( ) function because each implementation has its own
type for the variable which keeps track of whether the function
has been called , and there ' s no easy way to allocate the correct
size variable in code internal to Samba without knowing the
implementation ' s " once " type .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-05-12 09:33:32 +04:00
2009-05-13 17:49:59 +04:00
int smb_thread_once ( smb_thread_once_t * ponce ,
void ( * init_fn ) ( void * pdata ) ,
void * pdata )
2009-05-11 05:55:23 +04:00
{
int ret ;
/* Lock our "once" mutex in order to test and initialize ponce */
2009-05-13 22:31:40 +04:00
if ( SMB_THREAD_LOCK ( once_mutex ) ! = 0 ) {
2009-05-11 06:40:20 +04:00
smb_panic ( " error locking 'once' " ) ;
2009-05-11 05:55:23 +04:00
}
2009-05-13 17:49:59 +04:00
/* Keep track of whether we ran their init function */
ret = ! * ponce ;
2009-05-11 05:55:23 +04:00
/*
* See if another thread got here after we tested it initially but
* before we got our lock .
*/
2009-05-13 05:22:23 +04:00
if ( ! * ponce ) {
/* Nope, we need to run the initialization function */
2009-05-13 17:49:59 +04:00
( * init_fn ) ( pdata ) ;
2009-05-13 05:32:33 +04:00
/* Now we can indicate that the function has been run */
* ponce = true ;
2009-05-11 05:55:23 +04:00
}
/* Unlock the mutex */
2009-05-13 22:31:40 +04:00
if ( SMB_THREAD_UNLOCK ( once_mutex ) ! = 0 ) {
2009-05-11 06:40:20 +04:00
smb_panic ( " error unlocking 'once' " ) ;
2009-05-11 05:55:23 +04:00
}
2009-05-13 17:49:59 +04:00
/*
* Tell ' em whether we ran their init function . If they passed a data
* pointer to the init function and the init function could change
* something in the pointed - to data , this will tell them whether that
* data is valid or not .
*/
return ret ;
2009-05-11 05:55:23 +04:00
}
2009-04-09 02:46:49 +04:00
#if 0
/* Test. - pthread implementations. */
# include <pthread.h>
# ifdef malloc
# undef malloc
# endif
SMB_THREADS_DEF_PTHREAD_IMPLEMENTATION ( tf ) ;
2009-04-20 14:04:42 +04:00
static smb_thread_once_t ot = SMB_THREAD_ONCE_INIT ;
2009-04-15 02:19:39 +04:00
void * pkey = NULL ;
2009-04-20 14:04:42 +04:00
static void init_fn ( void )
{
int ret ;
if ( ! global_tfp ) {
/* Non-thread safe init case. */
if ( ot ) {
return ;
}
ot = true ;
}
if ( ( ret = SMB_THREAD_CREATE_TLS ( " test_tls " , pkey ) ) ! = 0 ) {
printf ( " Create tls once error: %d \n " , ret ) ;
}
}
2009-04-09 02:46:49 +04:00
/* Test function. */
int test_threads ( void )
{
int ret ;
void * plock = NULL ;
smb_thread_set_functions ( & tf ) ;
2009-04-20 14:04:42 +04:00
SMB_THREAD_ONCE ( & ot , init_fn ) ;
2009-04-09 02:46:49 +04:00
if ( ( ret = SMB_THREAD_CREATE_MUTEX ( " test " , plock ) ) ! = 0 ) {
printf ( " Create lock error: %d \n " , ret ) ;
}
if ( ( ret = SMB_THREAD_LOCK ( plock , SMB_THREAD_LOCK ) ) ! = 0 ) {
printf ( " lock error: %d \n " , ret ) ;
}
2009-05-11 05:55:23 +04:00
if ( ( ret = SMB_THREAD_LOCK ( plock , SMB_THREAD_UNLOCK ) ) ! = 0 ) {
2009-04-09 02:46:49 +04:00
printf ( " unlock error: %d \n " , ret ) ;
}
SMB_THREAD_DESTROY_MUTEX ( plock ) ;
2009-04-20 14:04:42 +04:00
SMB_THREAD_DESTROY_TLS ( pkey ) ;
2009-04-09 02:46:49 +04:00
return 0 ;
}
# endif