mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 15:50:51 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			566 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			566 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Copyright (C) 2000-2003 MySQL AB
 | |
| 
 | |
|    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 2 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, write to the Free Software
 | |
|    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | |
| 
 | |
| /* Functions to get threads more portable */
 | |
| 
 | |
| #define DONT_REMAP_PTHREAD_FUNCTIONS
 | |
| 
 | |
| #include "mysys_priv.h"
 | |
| #ifdef THREAD
 | |
| #include <signal.h>
 | |
| #include <m_string.h>
 | |
| #include <thr_alarm.h>
 | |
| #include <assert.h>
 | |
| 
 | |
| #if (defined(__BSD__) || defined(_BSDI_VERSION)) && !defined(HAVE_mit_thread)
 | |
| #define SCHED_POLICY SCHED_RR
 | |
| #else
 | |
| #define SCHED_POLICY SCHED_OTHER
 | |
| #endif
 | |
| 
 | |
| #ifndef my_pthread_setprio
 | |
| void my_pthread_setprio(pthread_t thread_id,int prior)
 | |
| {
 | |
| #ifdef HAVE_PTHREAD_SETSCHEDPARAM
 | |
|   struct sched_param tmp_sched_param;
 | |
|   bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
 | |
|   tmp_sched_param.sched_priority=prior;
 | |
|   VOID(pthread_setschedparam(thread_id,SCHED_POLICY,&tmp_sched_param));
 | |
| #endif
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #ifndef my_pthread_getprio
 | |
| int my_pthread_getprio(pthread_t thread_id)
 | |
| {
 | |
| #ifdef HAVE_PTHREAD_SETSCHEDPARAM
 | |
|   struct sched_param tmp_sched_param;
 | |
|   int policy;
 | |
|   if (!pthread_getschedparam(thread_id,&policy,&tmp_sched_param))
 | |
|   {
 | |
|     DBUG_PRINT("thread",("policy: %d  priority: %d",
 | |
| 			 policy,tmp_sched_param.sched_priority));
 | |
|     return tmp_sched_param.sched_priority;
 | |
|   }
 | |
| #endif
 | |
|   return -1;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #ifndef my_pthread_attr_setprio
 | |
| void my_pthread_attr_setprio(pthread_attr_t *attr, int priority)
 | |
| {
 | |
| #ifdef HAVE_PTHREAD_SETSCHEDPARAM
 | |
|   struct sched_param tmp_sched_param;
 | |
|   bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
 | |
|   tmp_sched_param.sched_priority=priority;
 | |
|   VOID(pthread_attr_setschedparam(attr,&tmp_sched_param));
 | |
| #endif
 | |
| }
 | |
| #endif
 | |
| 
 | |
| 
 | |
| /* To allow use of pthread_getspecific with two arguments */
 | |
| 
 | |
| #ifdef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
 | |
| #undef pthread_getspecific
 | |
| #ifdef HAVE_UNIXWARE7_THREADS
 | |
| #define pthread_getspecific thr_getspecific
 | |
| #endif
 | |
| 
 | |
| void *my_pthread_getspecific_imp(pthread_key_t key)
 | |
| {
 | |
|   void *value;
 | |
|   if (pthread_getspecific(key,(void *) &value))
 | |
|     return 0;
 | |
|   return value;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #ifdef __NETWARE__
 | |
| /*
 | |
|   Don't kill the LibC Reaper thread or the main thread
 | |
| */
 | |
| #include <nks/thread.h>
 | |
| #undef pthread_exit
 | |
| void my_pthread_exit(void *status)
 | |
| {
 | |
|   NXThreadId_t tid = NXThreadGetId();
 | |
|   NXContext_t ctx;
 | |
|   char name[PATH_MAX] = "";
 | |
| 
 | |
|   NXThreadGetContext(tid, &ctx);
 | |
|   NXContextGetName(ctx, name, PATH_MAX);
 | |
| 
 | |
|   /*
 | |
|     "MYSQLD.NLM's LibC Reaper" or "MYSQLD.NLM's main thread"
 | |
|     with a debug build of LibC the reaper can have different names
 | |
|   */
 | |
|   if (!strindex(name, "\'s"))
 | |
|   {
 | |
|     pthread_exit(status);
 | |
|   }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|   Some functions for RTS threads, AIX, Siemens Unix and UnixWare 7
 | |
|   (and DEC OSF/1 3.2 too)
 | |
| */
 | |
| 
 | |
| int my_pthread_create_detached=1;
 | |
| 
 | |
| #if defined(HAVE_NONPOSIX_SIGWAIT) || defined(HAVE_DEC_3_2_THREADS)
 | |
| 
 | |
| int my_sigwait(const sigset_t *set,int *sig)
 | |
| {
 | |
|   int signal=sigwait((sigset_t*) set);
 | |
|   if (signal < 0)
 | |
|     return errno;
 | |
|   *sig=signal;
 | |
|   return 0;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /* localtime_r for SCO 3.2V4.2 */
 | |
| 
 | |
| #if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
 | |
| 
 | |
| extern pthread_mutex_t LOCK_localtime_r;
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if !defined(HAVE_LOCALTIME_R)
 | |
| struct tm *localtime_r(const time_t *clock, struct tm *res)
 | |
| {
 | |
|   struct tm *tmp;
 | |
|   pthread_mutex_lock(&LOCK_localtime_r);
 | |
|   tmp=localtime(clock);
 | |
|   *res= *tmp;
 | |
|   pthread_mutex_unlock(&LOCK_localtime_r);
 | |
|   return res;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if !defined(HAVE_GMTIME_R)
 | |
| /* 
 | |
|   Reentrant version of standard gmtime() function. 
 | |
|   Needed on some systems which don't implement it.
 | |
| */
 | |
| 
 | |
| struct tm *gmtime_r(const time_t *clock, struct tm *res)
 | |
| {
 | |
|   struct tm *tmp;
 | |
|   pthread_mutex_lock(&LOCK_localtime_r);
 | |
|   tmp= gmtime(clock);
 | |
|   *res= *tmp;
 | |
|   pthread_mutex_unlock(&LOCK_localtime_r);
 | |
|   return res;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /****************************************************************************
 | |
| ** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
 | |
| **
 | |
| ** Note:
 | |
| ** This version of sigwait() is assumed to called in a loop so the signalmask
 | |
| ** is permanently modified to reflect the signal set. This is done to get
 | |
| ** a much faster implementation.
 | |
| **
 | |
| ** This implementation isn't thread safe: It assumes that only one
 | |
| ** thread is using sigwait.
 | |
| **
 | |
| ** If one later supplies a different signal mask, all old signals that
 | |
| ** was used before are unblocked and set to SIGDFL.
 | |
| **
 | |
| ** Author: Gary Wisniewski <garyw@spidereye.com.au>, much modified by Monty
 | |
| ****************************************************************************/
 | |
| 
 | |
| #if !defined(HAVE_SIGWAIT) && !defined(HAVE_mit_thread) && !defined(sigwait) && !defined(__WIN__) && !defined(HAVE_rts_threads) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS) && !defined(OS2)
 | |
| 
 | |
| #if !defined(DONT_USE_SIGSUSPEND)
 | |
| 
 | |
| static sigset_t sigwait_set,rev_sigwait_set,px_recd;
 | |
| 
 | |
| void px_handle_sig(int sig)
 | |
| {
 | |
|   sigaddset(&px_recd, sig);
 | |
| }
 | |
| 
 | |
| 
 | |
| void sigwait_setup(sigset_t *set)
 | |
| {
 | |
|   int i;
 | |
|   struct sigaction sact,sact1;
 | |
|   sigset_t unblock_mask;
 | |
| 
 | |
|   sact.sa_flags = 0;
 | |
|   sact.sa_handler = px_handle_sig;
 | |
|   memcpy_fixed(&sact.sa_mask,set,sizeof(*set));	/* handler isn't thread_safe */
 | |
|   sigemptyset(&unblock_mask);
 | |
|   pthread_sigmask(SIG_UNBLOCK,(sigset_t*) 0,&rev_sigwait_set);
 | |
| 
 | |
|   for (i = 1; i <= sizeof(sigwait_set)*8; i++)
 | |
|   {
 | |
|     if (sigismember(set,i))
 | |
|     {
 | |
|       sigdelset(&rev_sigwait_set,i);
 | |
|       if (!sigismember(&sigwait_set,i))
 | |
| 	sigaction(i, &sact, (struct sigaction*) 0);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       sigdelset(&px_recd,i);			/* Don't handle this */
 | |
|       if (sigismember(&sigwait_set,i))
 | |
|       {						/* Remove the old handler */
 | |
| 	sigaddset(&unblock_mask,i);
 | |
| 	sigdelset(&rev_sigwait_set,i);
 | |
| 	sact1.sa_flags = 0;
 | |
| 	sact1.sa_handler = SIG_DFL;
 | |
| 	sigemptyset(&sact1.sa_mask);
 | |
| 	sigaction(i, &sact1, 0);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   memcpy_fixed(&sigwait_set,set,sizeof(*set));
 | |
|   pthread_sigmask(SIG_BLOCK,(sigset_t*) set,(sigset_t*) 0);
 | |
|   pthread_sigmask(SIG_UNBLOCK,&unblock_mask,(sigset_t*) 0);
 | |
| }
 | |
| 
 | |
| 
 | |
| int sigwait(sigset_t *setp, int *sigp)
 | |
| {
 | |
|   if (memcmp(setp,&sigwait_set,sizeof(sigwait_set)))
 | |
|     sigwait_setup(setp);			/* Init or change of set */
 | |
| 
 | |
|   for (;;)
 | |
|   {
 | |
|     /*
 | |
|       This is a fast, not 100% portable implementation to find the signal.
 | |
|       Because the handler is blocked there should be at most 1 bit set, but
 | |
|       the specification on this is somewhat shady so we use a set instead a
 | |
|       single variable.
 | |
|       */
 | |
| 
 | |
|     ulong *ptr= (ulong*) &px_recd;
 | |
|     ulong *end=ptr+sizeof(px_recd)/sizeof(ulong);
 | |
| 
 | |
|     for ( ; ptr != end ; ptr++)
 | |
|     {
 | |
|       if (*ptr)
 | |
|       {
 | |
| 	ulong set= *ptr;
 | |
| 	int found= (int) ((char*) ptr - (char*) &px_recd)*8+1;
 | |
| 	while (!(set & 1))
 | |
| 	{
 | |
| 	  found++;
 | |
| 	  set>>=1;
 | |
| 	}
 | |
| 	*sigp=found;
 | |
| 	sigdelset(&px_recd,found);
 | |
| 	return 0;
 | |
|       }
 | |
|     }
 | |
|     sigsuspend(&rev_sigwait_set);
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| #else  /* !DONT_USE_SIGSUSPEND */
 | |
| 
 | |
| /****************************************************************************
 | |
| ** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
 | |
| **
 | |
| ** Note:
 | |
| ** This version of sigwait() is assumed to called in a loop so the signalmask
 | |
| ** is permanently modified to reflect the signal set. This is done to get
 | |
| ** a much faster implementation.
 | |
| **
 | |
| ** This implementation uses a extra thread to handle the signals and one
 | |
| ** must always call sigwait() with the same signal mask!
 | |
| **
 | |
| ** BSDI 3.0 NOTE:
 | |
| **
 | |
| ** pthread_kill() doesn't work on a thread in a select() or sleep() loop?
 | |
| ** After adding the sleep to sigwait_thread, all signals are checked and
 | |
| ** delivered every second. This isn't that terrible performance vice, but
 | |
| ** someone should report this to BSDI and ask for a fix!
 | |
| ** Another problem is that when the sleep() ends, every select() in other
 | |
| ** threads are interrupted!
 | |
| ****************************************************************************/
 | |
| 
 | |
| static sigset_t pending_set;
 | |
| static bool inited=0;
 | |
| static pthread_cond_t  COND_sigwait;
 | |
| static pthread_mutex_t LOCK_sigwait;
 | |
| 
 | |
| 
 | |
| void sigwait_handle_sig(int sig)
 | |
| {
 | |
|   pthread_mutex_lock(&LOCK_sigwait);
 | |
|   sigaddset(&pending_set, sig);
 | |
|   VOID(pthread_cond_signal(&COND_sigwait)); /* inform sigwait() about signal */
 | |
|   pthread_mutex_unlock(&LOCK_sigwait);
 | |
| }
 | |
| 
 | |
| extern pthread_t alarm_thread;
 | |
| 
 | |
| void *sigwait_thread(void *set_arg)
 | |
| {
 | |
|   sigset_t *set=(sigset_t*) set_arg;
 | |
| 
 | |
|   int i;
 | |
|   struct sigaction sact;
 | |
|   sact.sa_flags = 0;
 | |
|   sact.sa_handler = sigwait_handle_sig;
 | |
|   memcpy_fixed(&sact.sa_mask,set,sizeof(*set));	/* handler isn't thread_safe */
 | |
|   sigemptyset(&pending_set);
 | |
| 
 | |
|   for (i = 1; i <= sizeof(pending_set)*8; i++)
 | |
|   {
 | |
|     if (sigismember(set,i))
 | |
|     {
 | |
|       sigaction(i, &sact, (struct sigaction*) 0);
 | |
|     }
 | |
|   }
 | |
|   sigaddset(set,THR_CLIENT_ALARM);
 | |
|   pthread_sigmask(SIG_UNBLOCK,(sigset_t*) set,(sigset_t*) 0);
 | |
|   alarm_thread=pthread_self();			/* For thr_alarm */
 | |
| 
 | |
|   for (;;)
 | |
|   {						/* Wait for signals */
 | |
| #ifdef HAVE_NOT_BROKEN_SELECT
 | |
|     fd_set fd;
 | |
|     FD_ZERO(&fd);
 | |
|     select(0,&fd,0,0,0);
 | |
| #else
 | |
|     sleep(1);					/* Because of broken BSDI */
 | |
| #endif
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| int sigwait(sigset_t *setp, int *sigp)
 | |
| {
 | |
|   if (!inited)
 | |
|   {
 | |
|     pthread_attr_t thr_attr;
 | |
|     pthread_t sigwait_thread_id;
 | |
|     inited=1;
 | |
|     sigemptyset(&pending_set);
 | |
|     pthread_mutex_init(&LOCK_sigwait,MY_MUTEX_INIT_FAST);
 | |
|     pthread_cond_init(&COND_sigwait,NULL);
 | |
| 
 | |
|     pthread_attr_init(&thr_attr);
 | |
|     pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
 | |
|     pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
 | |
|     pthread_attr_setstacksize(&thr_attr,8196);
 | |
|     my_pthread_attr_setprio(&thr_attr,100);	/* Very high priority */
 | |
|     VOID(pthread_create(&sigwait_thread_id,&thr_attr,sigwait_thread,setp));
 | |
|     VOID(pthread_attr_destroy(&thr_attr));
 | |
|   }
 | |
| 
 | |
|   pthread_mutex_lock(&LOCK_sigwait);
 | |
|   for (;;)
 | |
|   {
 | |
|     ulong *ptr= (ulong*) &pending_set;
 | |
|     ulong *end=ptr+sizeof(pending_set)/sizeof(ulong);
 | |
| 
 | |
|     for ( ; ptr != end ; ptr++)
 | |
|     {
 | |
|       if (*ptr)
 | |
|       {
 | |
| 	ulong set= *ptr;
 | |
| 	int found= (int) ((char*) ptr - (char*) &pending_set)*8+1;
 | |
| 	while (!(set & 1))
 | |
| 	{
 | |
| 	  found++;
 | |
| 	  set>>=1;
 | |
| 	}
 | |
| 	*sigp=found;
 | |
| 	sigdelset(&pending_set,found);
 | |
| 	pthread_mutex_unlock(&LOCK_sigwait);
 | |
| 	return 0;
 | |
|       }
 | |
|     }
 | |
|     VOID(pthread_cond_wait(&COND_sigwait,&LOCK_sigwait));
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| #endif /* DONT_USE_SIGSUSPEND */
 | |
| #endif /* HAVE_SIGWAIT */
 | |
| 
 | |
| /*****************************************************************************
 | |
| ** Implement pthread_signal for systems that can't use signal() with threads
 | |
| ** Currently this is only used with BSDI 3.0
 | |
| *****************************************************************************/
 | |
| 
 | |
| #ifdef USE_PTHREAD_SIGNAL
 | |
| 
 | |
| int pthread_signal(int sig, void (*func)())
 | |
| {
 | |
|   struct sigaction sact;
 | |
|   sact.sa_flags= 0;
 | |
|   sact.sa_handler= func;
 | |
|   sigemptyset(&sact.sa_mask);
 | |
|   sigaction(sig, &sact, (struct sigaction*) 0);
 | |
|   return 0;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /****************************************************************************
 | |
|  The following functions fixes that all pthread functions should work
 | |
|  according to latest posix standard
 | |
| ****************************************************************************/
 | |
| 
 | |
| /* Undefined wrappers set my_pthread.h so that we call os functions */
 | |
| #undef pthread_mutex_init
 | |
| #undef pthread_mutex_lock
 | |
| #undef pthread_mutex_unlock
 | |
| #undef pthread_mutex_destroy
 | |
| #undef pthread_mutex_wait
 | |
| #undef pthread_mutex_timedwait
 | |
| #undef pthread_mutex_trylock
 | |
| #undef pthread_mutex_t
 | |
| #undef pthread_cond_init
 | |
| #undef pthread_cond_wait
 | |
| #undef pthread_cond_timedwait
 | |
| #undef pthread_cond_t
 | |
| #undef pthread_attr_getstacksize
 | |
| 
 | |
| /*****************************************************************************
 | |
| ** Patches for AIX and DEC OSF/1 3.2
 | |
| *****************************************************************************/
 | |
| 
 | |
| #if (defined(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT) && !defined(HAVE_UNIXWARE7_THREADS)) || defined(HAVE_DEC_3_2_THREADS)
 | |
| 
 | |
| #include <netdb.h>
 | |
| 
 | |
| int my_pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr)
 | |
| {
 | |
|   int error;
 | |
|   if (!attr)
 | |
|     error=pthread_mutex_init(mp,pthread_mutexattr_default);
 | |
|   else
 | |
|     error=pthread_mutex_init(mp,*attr);
 | |
|   return error;
 | |
| }
 | |
| 
 | |
| int my_pthread_cond_init(pthread_cond_t *mp, const pthread_condattr_t *attr)
 | |
| {
 | |
|   int error;
 | |
|   if (!attr)
 | |
|     error=pthread_cond_init(mp,pthread_condattr_default);
 | |
|   else
 | |
|     error=pthread_cond_init(mp,*attr);
 | |
|   return error;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| 
 | |
| /*****************************************************************************
 | |
|   Patches for HPUX
 | |
|   We need these because the pthread_mutex.. code returns -1 on error,
 | |
|   instead of the error code.
 | |
| 
 | |
|   Note that currently we only remap pthread_ functions used by MySQL.
 | |
|   If we are depending on the value for some other pthread_xxx functions,
 | |
|   this has to be added here.
 | |
| ****************************************************************************/
 | |
| 
 | |
| #if defined(HPUX10) || defined(HAVE_BROKEN_PTHREAD_COND_TIMEDWAIT)
 | |
| 
 | |
| int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
 | |
| 			      struct timespec *abstime)
 | |
| {
 | |
|   int error=pthread_cond_timedwait(cond, mutex, abstime);
 | |
|   if (error == -1)			/* Safety if the lib is fixed */
 | |
|   {
 | |
|     if (!(error=errno))
 | |
|       error= ETIMEDOUT;			/* Can happen on HPUX */
 | |
|   }
 | |
|   if (error == EAGAIN)			/* Correct errno to Posix */
 | |
|     error= ETIMEDOUT;
 | |
|   return error;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if defined(HPUX10)
 | |
| 
 | |
| void my_pthread_attr_getstacksize(pthread_attr_t *connection_attrib,
 | |
| 				  size_t *stack_size)
 | |
| {
 | |
|   *stack_size= pthread_attr_getstacksize(*connection_attrib);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| 
 | |
| #ifdef HAVE_POSIX1003_4a_MUTEX
 | |
| /*
 | |
|   In HP-UX-10.20 and other old Posix 1003.4a Draft 4 implementations
 | |
|   pthread_mutex_trylock returns 1 on success, not 0 like
 | |
|   pthread_mutex_lock
 | |
| 
 | |
|   From the HP-UX-10.20 man page:
 | |
|   RETURN VALUES
 | |
|       If the function fails, errno may be set to one of the following
 | |
|       values:
 | |
|            Return | Error    | Description
 | |
|            _______|__________|_________________________________________
 | |
|               1   |          | Successful completion.
 | |
|               0   |          | The mutex is  locked; therefore, it was
 | |
|                   |          | not acquired.
 | |
|              -1   | [EINVAL] | The value specified by mutex is invalid.
 | |
| 
 | |
| */
 | |
| 
 | |
| /*
 | |
|   Convert pthread_mutex_trylock to return values according to latest POSIX
 | |
| 
 | |
|   RETURN VALUES
 | |
|   0		If we are able successfully lock the mutex.
 | |
|   EBUSY		Mutex was locked by another thread
 | |
|   #		Other error number returned by pthread_mutex_trylock()
 | |
| 		(Not likely)  
 | |
| */
 | |
| 
 | |
| int my_pthread_mutex_trylock(pthread_mutex_t *mutex)
 | |
| {
 | |
|   int error= pthread_mutex_trylock(mutex);
 | |
|   if (error == 1)
 | |
|     return 0;				/* Got lock on mutex */
 | |
|   if (error == 0)			/* Someon else is locking mutex */
 | |
|     return EBUSY;
 | |
|   if (error == -1)			/* Safety if the lib is fixed */
 | |
|     error= errno;			/* Probably invalid parameter */
 | |
|    return error;
 | |
| }
 | |
| #endif /* HAVE_POSIX1003_4a_MUTEX */
 | |
| 
 | |
| /* Some help functions */
 | |
| 
 | |
| int pthread_no_free(void *not_used __attribute__((unused)))
 | |
| {
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int pthread_dummy(int ret)
 | |
| {
 | |
|   return ret;
 | |
| }
 | |
| #endif /* THREAD */
 | 
