Hi Henrik I've a primary simple model for libwww multi-threading. Here is my plain. Have a HTThread module and if the library is not defined to use threads then all the locking and unlocking functions always return true. But if the user wishes to use threads then the file will look something like this. /* * vuwThread.h * * This header file defines a pseduo thread interface locking and * unlocking mutexes in an effort to multi-thread w3lib. * * last modified: */ #ifndef _HTPORT_H_ #define _HTPORT_H_ #ifndef NO_THREADS #include "../vuwAnsi.h" #ifdef HAVE_P_THREADS #include #endif #ifdef HAVE_NT_THREADS #include #include /* The following flag is defined on the command line. #define _WIN32_WINNT 0x0400 */ /* some definitions to emulate posix conditional variables unded WIN32. Please check in vuwNtCondvar.c for complete implementation details */ typedef struct pthread_cond_t { int waiters_; // Number of waiting threads. CRITICAL_SECTION waiters_lock_; // Serialize access to the waiters count. HANDLE sema_; // Semaphore used to queue up threads waiting // for the condition to become signaled. HANDLE waiters_done_; // An auto reset event used by the broadcast/signal // thread to wait for all the waiting thread(s) to // wake up and be released from the semaphore. size_t was_broadcast_; // Keeps track of whether we were broadcasting // or signaling. This allows us to optimize the // code if we are just signaling. } pthread_cond_t; // Use a Win32 Mutex type for the POSIX pthread_mutex_t; typedef HANDLE pthread_mutex_t; typedef void pthread_condattr_t; // just to fake out pthread_condattr_t def typedef DWORD pthread_t; typedef HANDLE pthread_mutex_t; typedef void pthread_mutexattr_t; EXTERN int pthread_cond_init _ANSI_ARGS_ ((pthread_cond_t *cv, const pthread_condattr_t *notUsed)); EXTERN int pthread_cond_wait _ANSI_ARGS_ ((pthread_cond_t *cv, pthread_mutex_t *external_mutex)); EXTERN int pthread_cond_signal _ANSI_ARGS_ ((pthread_cond_t *cv)); EXTERN int pthread_cond_broadcast _ANSI_ARGS_ ((pthread_cond_t *cv)); EXTERN int pthread_mutex_lock _ANSI_ARGS_ ((pthread_mutex_t *mp)); EXTERN int pthread_mutex_unlock _ANSI_ARGS_ ((pthread_mutex_t *mp)); EXTERN int pthread_mutex_destroy _ANSI_ARGS_ ((pthread_mutex_t *mp)); EXTERN int pthread_mutex_init _ANSI_ARGS_ ((pthread_mutex_t *mp, pthread_mutexattr_t *unUsed)); EXTERN pthread_t pthread_self _ANSI_ARGS_ (()); #endif /* HAVE_NT_THREADS */ #else /* NO_THREADS */ typedef void pthread_mutex_t ; typedef void pthread_condattr_t; typedef void pthread_cond_t; #endif /* NO_THREADS */ extern int HTThread_acquireMutex _ANSI_ARGS_ ((pthread_mutex_t *mutexPtr)); extern int HTThread_releaseMutex _ANSI_ARGS_ ((pthread_mutex_t *mutexPtr)); extern int HTThread_releaseMutexAndSignal _ANSI_ARGS_ ( (pthread_mutex_t *mutexPtr) (pthread_cond_t *cvPtr)); #endif /* _HTPORT_H_ */ /* * vuwThread.c * * This header file implemets a pseduo thread interface locking and * unlocking mutexes in an effort to multi-thread w3lib. * * last modified: */ #include "HTThread.h" /*----------------------------------------------------------------------------- * * AcquireMutex -- * ReleaseMutexAndSignal -- * * These two functions are similar to AcquireProgLock and ReleaseProgLock * except that instead of operating on connection specific mutext and * conditional variables these functions are called on any mutext and * conditional variables. Acquire Mutex is called to acquire a lock on a * given mutex. ReleaseMutexAndSignal is called to release the lock on * the given mutext that had all ready been acquired and signal the given * conditional variable. The parameters cHndl, who and context are used * for tracing any of them can be null or invalid. * * Results: * AcquireMutex tries to acquire a lock on the given * mutex. ReleaseMutexAndSignal will release the lock on pre-aqcuired * mutex; it optionally can signal a conditional variable if one * (non-null) is provided. * * Side effects: * none in terms of memory but could be on the basis os * synchornization * depeding upon the lock *----------------------------------------------------------------------------- */ #ifdef NO_THREADS int pthread_mutex_lock(mutexPtr) pthread_mutex_t *mutexPtr; { return 0; } int pthread_mutex_unlock(mutexPtr) pthread_mutex_t *mutexPtr; { return 0; } int pthread_cond_signal( cvPtr) pthread_cond_t *cvPtr; { return 0; } #endif int HTThread_acquireMutex ( mutexPtr) pthread_mutex_t *mutexPtr; { if(!mutexPtr) return 0; return(pthread_mutex_lock(mutexPtr)); } int HTThreads_releaseMutex( mutexPtr) pthread_mutex_t *mutexPtr; { if(!mutexPtr) return 0; return (pthread_mutex_unlock(mutexPtr)); } int HTThreads_releaseMutexAndSignal( mutexPtr, cvPtr) pthread_mutex_t *mutexPtr; pthread_cond_t *cvPtr; { if(!mutexPtr || !cvPtr) return 0; if(cvPtr != (pthread_cond_t *)NULL) { pthread_cond_signal(cvPtr); } return (pthread_mutex_unlock(mutexPtr)); } The Net module for example will define 2 new API's for it synchronization. extern void HTNet_setAccessMutex (pthread_mutex_t *mutexPtr); extern pthread_mutex_t *HTNet_accessMutex (void); The additional code that will be needed in HTNet.c will be /* Net lock module */ PRIVATE pthread_mutex_t *AccessMutex=NULL; /* mutex for accessing shared */ PUBLIC void HTNet_setAccessMutex (pthread_mutex_t *mutexPtr) { if(mutexPtr) AccessMutex = mutexPtr; } PUBLIC pthread_mutex_t* HTNet_accessMutex () { return AccessMutex; } #define LOCK HTThread_acquireMutex(AccessMutex); #define UNLOCK HTThread_releaseMutex(AccessMutex); so whenever synchonization is needed just use LOCK before and UNLOCK when done. for example HTNet_increaseSocket will be modified like this. PUBLIC void HTNet_increaseSocket (void) { LOCK; Active++; if (CORE_TRACE) HTTrace("Net Manager. Increasing active sockets to %d, %d persistent sockets\n", Active, Persistent); UNLOCK; } One thing the user needs to do if he is using threas is to initialize all the thread module. Here is how that can be done for various modules /* * declare mutexes for w3-access modules. These are necessary to make w3-lib * multi-threaded */ static pthread_mutex_t dnsAccessMutex; /* w3-DNS module access */ static pthread_mutex_t netAccessMutex; /* w3-NET module access */ static pthread_mutex_t hostAccessMutex; /* w3-host access module */ static pthread_mutex_t anchorAccessMutex; /* w3-Anchor access module */ static pthread_mutex_t channelAccessMutex; /* w3-channel access module */ /* * Initialize and set w3-lib access mutexes. */ pthread_mutex_init(&dnsAccessMutex, (pthread_mutexattr_t *)NULL); HTDNS_setAccessMutex(&dnsAccessMutex); pthread_mutex_init(&netAccessMutex, (pthread_mutexattr_t *)NULL); HTNet_setAccessMutex(&dnsAccessMutex); pthread_mutex_init(&hostAccessMutex, (pthread_mutexattr_t *)NULL); HTHost_setAccessMutex(&dnsAccessMutex); pthread_mutex_init(&anchorAccessMutex, (pthread_mutexattr_t *)NULL); HTAnchor_setAccessMutex(&dnsAccessMutex); pthread_mutex_init(&channelAccessMutex, (pthread_mutexattr_t *)NULL); HTChannel_setAccessMutex(&dnsAccessMutex); I also made a cheap emulation of some of posix thread emulations using WIN32 API. I can send that file later. Please let me know what you think of this. I've a working version of this code used to make w3lib thread safe. Let me know what you think of this Thanks