From: Stefan Csomor Date: Tue, 10 Jun 2008 18:59:48 +0000 (+0000) Subject: removing outdated files on mac X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/266fe3655f25ce8e4cfb452eee794691971a12ef removing outdated files on mac git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@54078 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/src/mac/carbon/aga.cpp b/src/mac/carbon/aga.cpp deleted file mode 100644 index 543fc10137..0000000000 --- a/src/mac/carbon/aga.cpp +++ /dev/null @@ -1,2 +0,0 @@ -// NOT NEEDED ANYMORE - diff --git a/src/mac/carbon/gsocket.cpp b/src/mac/carbon/gsocket.cpp deleted file mode 100644 index 123d9cd6b5..0000000000 --- a/src/mac/carbon/gsocket.cpp +++ /dev/null @@ -1,1649 +0,0 @@ -/* ------------------------------------------------------------------------- - * Project: GSocket (Generic Socket) for WX - * Name: src/mac/carbon/gsocket.cpp - * Copyright: (c) Guilhem Lavaux - * Licence: wxWindows Licence - * Authors: Guilhem Lavaux, - * Guillermo Rodriguez Garcia (maintainer) - * Stefan CSomor - * Purpose: GSocket main mac file - * CVSID: $Id$ - * ------------------------------------------------------------------------- - */ - -/* - * PLEASE don't put C++ comments here - this is a C source file. - */ - -#ifndef __GSOCKET_STANDALONE__ -#include "wx/platform.h" -#endif - -#if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) - -#ifdef __DARWIN__ - #include -#else - #include - #define OTUNIXERRORS 1 - #include - #include - #include -#endif -#if TARGET_CARBON && !defined(OTAssert) - #define OTAssert( str , cond ) /* does not exists in Carbon */ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * INADDR_BROADCAST is identical to INADDR_NONE which is not defined - * on all unices. INADDR_BROADCAST should be fine to indicate an error. - */ -#ifndef INADDR_BROADCAST -#define INADDR_BROADCAST 0xFFFFFFFFUL -#endif -#ifndef INADDR_NONE -#define INADDR_NONE INADDR_BROADCAST -#endif -#ifndef INADDR_ANY -#define INADDR_ANY 0x0UL -#endif -#ifndef __GSOCKET_STANDALONE__ - - #include "wx/mac/macnotfy.h" - #include "wx/mac/gsockmac.h" - #include "wx/gsocket.h" - -#else - - #include "gsockmac.h" - #include "gsocket.h" - -#endif /* __GSOCKET_STANDALONE__ */ - -#ifndef ntohl - #define ntohl(x) (x) - #define ntohs(x) (x) - #define htonl(x) (x) - #define htons(x) (x) -#endif - -void wxCYield() ; -#ifdef __WXDEBUG__ -#define qDebug 1 -#define qDebug2 1 -extern pascal void OTDebugStr(const char* str); -#endif -#ifndef __DARWIN__ - #include -#endif -InetSvcRef gInetSvcRef = 0 ; -int gOTInited = 0 ; -OTNotifyUPP gOTNotifierUPP = NULL ; - -OSStatus DoNegotiateIPReuseAddrOption(EndpointRef ep, Boolean enableReuseIPMode); - -/* Input: ep - endpointref on which to negotiate the option - enableReuseIPMode - desired option setting - true/false - Return: kOTNoError indicates that the option was successfully negotiated - OSStatus is an error if < 0, otherwise, the status field is - returned and is > 0. - - IMPORTANT NOTE: The endpoint is assumed to be in synchronous more, otherwise - this code will not function as desired -*/ - - -OSStatus DoNegotiateIPReuseAddrOption(EndpointRef ep, Boolean enableReuseIPMode) - -{ - UInt8 buf[kOTFourByteOptionSize]; // define buffer for fourByte Option size - TOption* opt; // option ptr to make items easier to access - TOptMgmt req; - TOptMgmt ret; - OSStatus err; - - if (!OTIsSynchronous(ep)) - { - return (-1); - } - opt = (TOption*)buf; // set option ptr to buffer - req.opt.buf = buf; - req.opt.len = sizeof(buf); - req.flags = T_NEGOTIATE; // negotiate for option - - ret.opt.buf = buf; - ret.opt.maxlen = kOTFourByteOptionSize; - - opt->level = INET_IP; // dealing with an IP Level function -#ifdef __DARWIN__ - opt->name = kIP_REUSEADDR; -#else - opt->name = IP_REUSEADDR; -#endif - opt->len = kOTFourByteOptionSize; - opt->status = 0; - *(UInt32*)opt->value = enableReuseIPMode; // set the desired option level, true or false - - err = OTOptionManagement(ep, &req, &ret); - - // if no error then return the option status value - if (err == kOTNoError) - { - if (opt->status != T_SUCCESS) - err = opt->status; - else - err = kOTNoError; - } - - return err; -} - - -pascal void OTInetEventHandler(void*s, OTEventCode event, OTResult, void *cookie) ; -pascal void OTInetEventHandler(void*s, OTEventCode event, OTResult result, void *cookie) -{ - int wakeUp = true ; - GSocket* sock = (GSocket*) s ; - - if ( event == kOTSyncIdleEvent ) - { - return ; - } - - if ( s ) - { - wxMacAddEvent( sock->m_mac_events , _GSocket_Internal_Proc , event , s , wakeUp ) ; - } - - return; -} - -static void SetDefaultEndpointModes(EndpointRef ep , void *data ) - // This routine sets the supplied endpoint into the default - // mode used in this application. The specifics are: - // blocking, synchronous, and using synch idle events with - // the standard YieldingNotifier. -{ - OSStatus junk = kOTNoError ; - OTAssert ("SetDefaultEndpointModes:invalid ref", ep != kOTInvalidEndpointRef ) ; - junk = OTSetAsynchronous(ep); - OTAssert("SetDefaultEndpointModes: Could not set asynchronous", junk == noErr); -/* - junk = OTSetBlocking(ep); - OTAssert("SetDefaultEndpointModes: Could not set blocking", junk == noErr); - junk = OTSetSynchronous(ep); - OTAssert("SetDefaultEndpointModes: Could not set synchronous", junk == noErr); - junk = OTSetBlocking(ep); - OTAssert("SetDefaultEndpointModes: Could not set blocking", junk == noErr); -*/ - junk = OTInstallNotifier(ep, gOTNotifierUPP, data); - OTAssert("SetDefaultEndpointModes: Could not install notifier", junk == noErr); -/* - junk = OTUseSyncIdleEvents(ep, true); - OTAssert("SetDefaultEndpointModes: Could not use sync idle events", junk == noErr); -*/ -} - -bool GSocket_Init() -{ - return true; -} - -bool GSocket_Verify_Inited() -{ - OSStatus err ; -#if TARGET_CARBON - // Marc Newsam: added the clientcontext variable - // however, documentation is unclear how this works - OTClientContextPtr clientcontext; - - if ( gInetSvcRef ) - return true ; - - InitOpenTransportInContext(kInitOTForApplicationMask, &clientcontext); - gOTInited = 1 ; - gInetSvcRef = OTOpenInternetServicesInContext(kDefaultInternetServicesPath, - NULL, &err, clientcontext); -#else - if ( gInetSvcRef ) - return true ; - - InitOpenTransport() ; - gOTInited = 1 ; - gInetSvcRef = OTOpenInternetServices(kDefaultInternetServicesPath, NULL, &err); -#endif - if ( gInetSvcRef == NULL || err != kOTNoError ) - { - OTAssert("Could not open Inet Services", err == noErr); - return false ; - } - gOTNotifierUPP = NewOTNotifyUPP( OTInetEventHandler ) ; - return true ; -} - -void GSocket_Cleanup() -{ - if ( gOTInited != 0 ) - { - if ( gInetSvcRef != NULL ) - OTCloseProvider( gInetSvcRef ); - #if TARGET_CARBON - CloseOpenTransportInContext( NULL ) ; - #else - CloseOpenTransport() ; - #endif - if ( gOTNotifierUPP ) - DisposeOTNotifyUPP( gOTNotifierUPP ) ; - } -} - -/* Constructors / Destructors for GSocket */ - -GSocket::GSocket() -{ - int i; - - m_ok = GSocket_Verify_Inited(); - - m_endpoint = NULL ; - for (i=0;im_family == GSOCK_NOFAMILY) - { - m_error = GSOCK_INVADDR; - return GSOCK_INVADDR; - } - - if (m_local) - GAddress_destroy(m_local); - - m_local = GAddress_copy(address); - - return GSOCK_NOERROR; -} - -GSocketError GSocket::SetPeer(GAddress *address) -{ - assert(this); - - /* check address */ - if (address == NULL || address->m_family == GSOCK_NOFAMILY) - { - m_error = GSOCK_INVADDR; - return GSOCK_INVADDR; - } - - if (m_peer) - GAddress_destroy(m_peer); - - m_peer = GAddress_copy(address); - - return GSOCK_NOERROR; -} - -GAddress *GSocket::GetLocal() -{ - GAddress *address = NULL ; - GSocketError err; - InetAddress loc ; - - assert(this); - - /* try to get it from the m_local var first */ - if (m_local) - return GAddress_copy(m_local); - - /* else, if the socket is initialized, try getsockname */ - if (m_endpoint == kOTInvalidEndpointRef) - { - m_error = GSOCK_INVSOCK; - return NULL; - } - - -/* we do not support multihoming with this code at the moment - OTGetProtAddress will have to be used then - but we don't have a handy - method to use right now -*/ - { - InetInterfaceInfo info; - OTInetGetInterfaceInfo(&info, kDefaultInetInterface); - loc.fHost = info.fAddress ; - loc.fPort = 0 ; - loc.fAddressType = AF_INET ; - } - - /* got a valid address from getsockname, create a GAddress object */ - address = GAddress_new(); - if (address == NULL) - { - m_error = GSOCK_MEMERR; - return NULL; - } - - err = _GAddress_translate_from(address, &loc); - if (err != GSOCK_NOERROR) - { - GAddress_destroy(address); - m_error = err; - return NULL; - } - - return address; -} - -GAddress *GSocket::GetPeer() -{ - assert(this); - - /* try to get it from the m_peer var */ - if (m_peer) - return GAddress_copy(m_peer); - - return NULL; -} - -/* Server specific parts */ - -/* GSocket_SetServer: - * Sets up this socket as a server. The local address must have been - * set with GSocket_SetLocal() before GSocket_SetServer() is called. - * Returns GSOCK_NOERROR on success, one of the following otherwise: - * - * Error codes: - * GSOCK_INVSOCK - the socket is in use. - * GSOCK_INVADDR - the local address has not been set. - * GSOCK_IOERR - low-level error. - */ -GSocketError GSocket::SetServer() -{ - assert(this); - - /* must not be in use */ - if (m_endpoint != kOTInvalidEndpointRef ) - { - m_error = GSOCK_INVSOCK; - return GSOCK_INVSOCK; - } - - /* the local addr must have been set */ - if (!m_local) - { - m_error = GSOCK_INVADDR; - return GSOCK_INVADDR; - } - - /* Initialize all fields */ - m_stream = true; - m_server = true; - m_oriented = true; - -// TODO -#if 0 - /* Create the socket */ - m_endpoint = socket(m_local->m_realfamily, SOCK_STREAM, 0); - socket_set_ref( m_endpoint , (unsigned long) &gMacNetEvents , (unsigned long) this ) ; - if (m_endpoint == kOTInvalidEndpointRef) - { - m_error = GSOCK_IOERR; - return GSOCK_IOERR; - } - - ioctl(m_endpoint, FIONBIO, &arg); - Enable_Events(); - - /* Bind to the local address, - * retrieve the actual address bound, - * and listen up to 5 connections. - */ - if ((bind(m_endpoint, m_local->m_addr, m_local->m_len) != 0) || - (getsockname(m_endpoint, - m_local->m_addr, - (WX_SOCKLEN_T *) &m_local->m_len) != 0) || - (listen(m_endpoint, 5) != 0)) - { - close(m_endpoint); - m_endpoint = -1; - m_error = GSOCK_IOERR; - return GSOCK_IOERR; - } -#endif - return GSOCK_NOERROR; -} - -/* GSocket_WaitConnection: - * Waits for an incoming client connection. Returns a pointer to - * a GSocket object, or NULL if there was an error, in which case - * the last error field will be updated for the calling GSocket. - * - * Error codes (set in the calling GSocket) - * GSOCK_INVSOCK - the socket is not valid or not a server. - * GSOCK_TIMEDOUT - timeout, no incoming connections. - * GSOCK_WOULDBLOCK - the call would block and the socket is nonblocking. - * GSOCK_MEMERR - couldn't allocate memory. - * GSOCK_IOERR - low-level error. - */ -GSocket *GSocket::WaitConnection() -{ - GSocket *connection = NULL ; - - assert(this); - - /* Reenable CONNECTION events */ - m_detected &= ~GSOCK_CONNECTION_FLAG; - - /* If the socket has already been created, we exit immediately */ - if (m_endpoint == kOTInvalidEndpointRef || !m_server) - { - m_error = GSOCK_INVSOCK; - return NULL; - } - - /* Create a GSocket object for the new connection */ - connection = GSocket_new(); - - if (!connection) - { - m_error = GSOCK_MEMERR; - return NULL; - } - - /* Wait for a connection (with timeout) */ - if (Input_Timeout() == GSOCK_TIMEDOUT) - { - delete connection; - /* m_error set by _GSocket_Input_Timeout */ - return NULL; - } - -// TODO -#if 0 - connection->m_endpoint = accept(m_endpoint, &from, (WX_SOCKLEN_T *) &fromlen); -#endif - - if (connection->m_endpoint == kOTInvalidEndpointRef ) - { - if (errno == EWOULDBLOCK) - m_error = GSOCK_WOULDBLOCK; - else - m_error = GSOCK_IOERR; - - delete connection; - return NULL; - } - - /* Initialize all fields */ - connection->m_server = false; - connection->m_stream = true; - connection->m_oriented = true; - - /* Setup the peer address field */ - connection->m_peer = GAddress_new(); - if (!connection->m_peer) - { - delete connection; - m_error = GSOCK_MEMERR; - return NULL; - } - // TODO - #if 0 - err = _GAddress_translate_from(connection->m_peer, &from, fromlen); - if (err != GSOCK_NOERROR) - { - GAddress_destroy(connection->m_peer); - GSocket_destroy(connection); - m_error = err; - return NULL; - } - - ioctl(connection->m_endpoint, FIONBIO, &arg); -#endif - connection->Enable_Events(); - - return connection; -} - -/* Datagram sockets */ - -/* GSocket_SetNonOriented: - * Sets up this socket as a non-connection oriented (datagram) socket. - * Before using this function, the local address must have been set - * with GSocket_SetLocal(), or the call will fail. Returns GSOCK_NOERROR - * on success, or one of the following otherwise. - * - * Error codes: - * GSOCK_INVSOCK - the socket is in use. - * GSOCK_INVADDR - the local address has not been set. - * GSOCK_IOERR - low-level error. - */ -GSocketError GSocket::SetNonOriented() -{ - assert(this); - - if (m_endpoint != kOTInvalidEndpointRef ) - { - m_error = GSOCK_INVSOCK; - return GSOCK_INVSOCK; - } - - if (!m_local) - { - m_error = GSOCK_INVADDR; - return GSOCK_INVADDR; - } - - /* Initialize all fields */ - m_stream = false; - m_server = false; - m_oriented = false; - - /* Create the socket */ - -// TODO -#if 0 - m_endpoint = socket(m_local->m_realfamily, SOCK_DGRAM, 0); - socket_set_ref( m_endpoint , (unsigned long) &gMacNetEvents , (unsigned long) this ) ; -#endif - if (m_endpoint == kOTInvalidEndpointRef ) - { - m_error = GSOCK_IOERR; - return GSOCK_IOERR; - } - -// TODO -#if 0 - ioctl(m_endpoint, FIONBIO, &arg); -#endif - Enable_Events(); - - /* Bind to the local address, - * and retrieve the actual address bound. - */ -// TODO -#if 0 - if ((bind(m_endpoint, m_local->m_addr, m_local->m_len) != 0) || - (getsockname(m_endpoint, - m_local->m_addr, - (WX_SOCKLEN_T *) &m_local->m_len) != 0)) - { - close(m_endpoint); - m_endpoint = -1; - m_error = GSOCK_IOERR; - return GSOCK_IOERR; - } -#endif - return GSOCK_NOERROR; -} - -/* Client specific parts */ - -/* GSocket_Connect: - * For stream (connection oriented) sockets, GSocket_Connect() tries - * to establish a client connection to a server using the peer address - * as established with GSocket_SetPeer(). Returns GSOCK_NOERROR if the - * connection has been successfully established, or one of the error - * codes listed below. Note that for nonblocking sockets, a return - * value of GSOCK_WOULDBLOCK doesn't mean a failure. The connection - * request can be completed later; you should use GSocket_Select() - * to poll for GSOCK_CONNECTION | GSOCK_LOST, or wait for the - * corresponding asynchronous events. - * - * For datagram (non connection oriented) sockets, GSocket_Connect() - * just sets the peer address established with GSocket_SetPeer() as - * default destination. - * - * Error codes: - * GSOCK_INVSOCK - the socket is in use or not valid. - * GSOCK_INVADDR - the peer address has not been established. - * GSOCK_TIMEDOUT - timeout, the connection failed. - * GSOCK_WOULDBLOCK - connection in progress (nonblocking sockets only) - * GSOCK_MEMERR - couldn't allocate memory. - * GSOCK_IOERR - low-level error. - */ -GSocketError GSocket::Connect(GSocketStream stream) -{ - InetAddress addr ; - TEndpointInfo info; - OSStatus err = kOTNoError; - TCall peer ; - - assert(this); - - /* Enable CONNECTION events (needed for nonblocking connections) */ - m_detected &= ~GSOCK_CONNECTION_FLAG; - - if (m_endpoint != kOTInvalidEndpointRef ) - { - m_error = GSOCK_INVSOCK; - return GSOCK_INVSOCK; - } - - if (!m_peer) - { - m_error = GSOCK_INVADDR; - return GSOCK_INVADDR; - } - - /* Streamed or dgram socket? */ - m_stream = (stream == GSOCK_STREAMED); - m_oriented = true; - m_server = false; - - /* Create the socket */ -#if TARGET_CARBON - m_endpoint = - OTOpenEndpointInContext( OTCreateConfiguration( kTCPName) , 0 , &info , &err , NULL ) ; -#else - m_endpoint = - OTOpenEndpoint( OTCreateConfiguration( kTCPName) , 0 , &info , &err ) ; -#endif - if ( m_endpoint == kOTInvalidEndpointRef || err != kOTNoError ) - { - m_endpoint = kOTInvalidEndpointRef ; - m_error = GSOCK_IOERR; - return GSOCK_IOERR; - } - err = OTBind( m_endpoint , nil , nil ) ; - if ( err != kOTNoError ) - { - return GSOCK_IOERR; - } - SetDefaultEndpointModes( m_endpoint , this ) ; -// TODO -#if 0 - ioctl(m_endpoint, FIONBIO, &arg); -#endif - Enable_Events(); - - _GAddress_translate_to( m_peer , &addr ) ; - memset( &peer , 0 , sizeof( TCall ) ) ; - peer.addr.len = sizeof( InetAddress ) ; - peer.addr.buf = (unsigned char*) &addr ; - err = OTConnect( m_endpoint , &peer , nil ) ; - if ( err != noErr ) - { - /* If connect failed with EINPROGRESS and the GSocket object - * is in blocking mode, we select() for the specified timeout - * checking for writability to see if the connection request - * completes. - */ - - if ((err == kOTNoDataErr ) && (!m_non_blocking)) - { - if (Output_Timeout() == GSOCK_TIMEDOUT) - { - OTSndOrderlyDisconnect( m_endpoint ) ; - m_endpoint = kOTInvalidEndpointRef ; - /* m_error is set in _GSocket_Output_Timeout */ - return GSOCK_TIMEDOUT; - } - else - { -/* - int error; - WX_SOCKLEN_T len = sizeof(error); - - getsockopt(m_endpoint, SOL_SOCKET, SO_ERROR, (void*) &error, &len); - - if (!error) -*/ - return GSOCK_NOERROR; - } - } - - /* If connect failed with EINPROGRESS and the GSocket object - * is set to nonblocking, we set m_error to GSOCK_WOULDBLOCK - * (and return GSOCK_WOULDBLOCK) but we don't close the socket; - * this way if the connection completes, a GSOCK_CONNECTION - * event will be generated, if enabled. - */ - if ((err == kOTNoDataErr) && (m_non_blocking)) - { - m_error = GSOCK_WOULDBLOCK; - return GSOCK_WOULDBLOCK; - } - - /* If connect failed with an error other than EINPROGRESS, - * then the call to GSocket_Connect has failed. - */ - OTSndOrderlyDisconnect( m_endpoint ) ; - - m_endpoint = kOTInvalidEndpointRef ; - m_error = GSOCK_IOERR; - return GSOCK_IOERR; - } -// OTInetEventHandler(this, T_CONNECT , kOTNoError , NULL ) ; - return GSOCK_NOERROR; -} - -/* Generic IO */ - -/* Like recv(), send(), ... */ -int GSocket::Read(char *buffer, int size) -{ - int ret = 0 ; - - assert(this); - - /* Reenable INPUT events */ - m_detected &= ~GSOCK_INPUT_FLAG; - - if (m_endpoint == kOTInvalidEndpointRef || m_server) - { - m_error = GSOCK_INVSOCK; - return -1; - } - - /* If the socket is blocking, wait for data (with a timeout) */ - if (Input_Timeout() == GSOCK_TIMEDOUT) - return -1; - - /* Read the data */ - if (m_stream) - ret = Recv_Stream(buffer, size); - else - ret = Recv_Dgram(buffer, size); - - if (ret == -1) - { - if (errno == EWOULDBLOCK) - m_error = GSOCK_WOULDBLOCK; - else - m_error = GSOCK_IOERR; - } - - return ret; -} - -int GSocket::Write(const char *buffer, int size) -{ - int ret; - - assert(this); - - if (m_endpoint == kOTInvalidEndpointRef || m_server) - { - m_error = GSOCK_INVSOCK; - return -1; - } - - /* If the socket is blocking, wait for writability (with a timeout) */ - if (Output_Timeout() == GSOCK_TIMEDOUT) - return -1; - - /* Write the data */ - if (m_stream) - ret = Send_Stream(buffer, size); - else - ret = Send_Dgram(buffer, size); - - if (ret == -1) - { - if (errno == EWOULDBLOCK) - m_error = GSOCK_WOULDBLOCK; - else - m_error = GSOCK_IOERR; - - /* Only reenable OUTPUT events after an error (just like WSAAsyncSelect - * in MSW). Once the first OUTPUT event is received, users can assume - * that the socket is writable until a read operation fails. Only then - * will further OUTPUT events be posted. - */ - m_detected &= ~GSOCK_OUTPUT_FLAG; - return -1; - } - - return ret; -} - -/* GSocket_Select: - * Polls the socket to determine its status. This function will - * check for the events specified in the 'flags' parameter, and - * it will return a mask indicating which operations can be - * performed. This function won't block, regardless of the - * mode (blocking | nonblocking) of the socket. - */ -GSocketEventFlags GSocket::Select(GSocketEventFlags flags) -{ - assert(this); - wxMacProcessNotifierEvents() ; - /* - state = OTGetEndpointState(m_endpoint); - - if ( ( flags & GSOCK_INPUT_FLAG ) && ! ( m_detected & GSOCK_INPUT_FLAG ) ) - { - size_t sz = 0 ; - OTCountDataBytes( m_endpoint , &sz ) ; - if ( state == T_INCON || sz > 0 ) - { - m_detected |= GSOCK_INPUT_FLAG ; - (m_cbacks[GSOCK_INPUT])(this, GSOCK_INPUT, m_data[GSOCK_INPUT]); - } - } - if ( ( flags & GSOCK_INPUT_FLAG ) && ! ( m_detected & GSOCK_OUTPUT_FLAG ) ) - { - if ( state == T_DATAXFER || state == T_INREL ) - { - m_detected |=GSOCK_OUTPUT_FLAG ; - (m_cbacks[GSOCK_OUTPUT])(this, GSOCK_OUTPUT, m_data[GSOCK_OUTPUT]); - } - } - */ - return ( flags & m_detected ) ; -} - -/* Flags */ - -/* GSocket_SetNonBlocking: - * Sets the socket to non-blocking mode. All IO calls will return - * immediately. - */ -void GSocket::SetNonBlocking(bool non_block) -{ - assert(this); - - m_non_blocking = non_block; -} - -/* GSocket_SetTimeout: - * Sets the timeout for blocking calls. Time is expressed in - * milliseconds. - */ -void GSocket::SetTimeout(unsigned long millisec) -{ - assert(this); - -// this is usually set too high and we have not yet been able to detect a closed -// stream, thus we leave the 10 sec timeout -// m_timeout = millisec; -} - -/* GSocket_GetError: - * Returns the last error which occurred for this socket. Note that successful - * operations do not clear this back to GSOCK_NOERROR, so use it only - * after an error. - */ -GSocketError WXDLLIMPEXP_NET GSocket::GetError() -{ - assert(this); - - return m_error; -} - -/* Callbacks */ - -/* GSOCK_INPUT: - * There is data to be read in the input buffer. If, after a read - * operation, there is still data available, the callback function will - * be called again. - * GSOCK_OUTPUT: - * The socket is available for writing. That is, the next write call - * won't block. This event is generated only once, when the connection is - * first established, and then only if a call failed with GSOCK_WOULDBLOCK, - * when the output buffer empties again. This means that the app should - * assume that it can write since the first OUTPUT event, and no more - * OUTPUT events will be generated unless an error occurs. - * GSOCK_CONNECTION: - * Connection successfully established, for client sockets, or incoming - * client connection, for server sockets. Wait for this event (also watch - * out for GSOCK_LOST) after you issue a nonblocking GSocket_Connect() call. - * GSOCK_LOST: - * The connection is lost (or a connection request failed); this could - * be due to a failure, or due to the peer closing it gracefully. - */ - -/* GSocket_SetCallback: - * Enables the callbacks specified by 'flags'. Note that 'flags' - * may be a combination of flags OR'ed toghether, so the same - * callback function can be made to accept different events. - * The callback function must have the following prototype: - * - * void function(GSocket *socket, GSocketEvent event, char *cdata) - */ -void GSocket::SetCallback(GSocketEventFlags flags, - GSocketCallback callback, char *cdata) -{ - int count; - - assert(this); - - for (count = 0; count < GSOCK_MAX_EVENT; count++) - { - if ((flags & (1 << count)) != 0) - { - m_cbacks[count] = callback; - m_data[count] = cdata; - } - } -} - -/* GSocket_UnsetCallback: - * Disables all callbacks specified by 'flags', which may be a - * combination of flags OR'ed toghether. - */ -void GSocket::UnsetCallback(GSocketEventFlags flags) -{ - int count; - - assert(this); - - for (count = 0; count < GSOCK_MAX_EVENT; count++) - { - if ((flags & (1 << count)) != 0) - { - m_cbacks[count] = NULL; - m_data[count] = NULL; - } - } -} - - -#define CALL_CALLBACK(socket, event) { \ - _GSocket_Disable(socket, event); \ - if (socket->m_cbacks[event]) \ - socket->m_cbacks[event](socket, event, socket->m_data[event]); \ -} - -int GSocket::Recv_Stream(char *buffer, int size) -{ - OTFlags flags ; - OTResult res ; - OTByteCount sz = 0 ; - - OTCountDataBytes( m_endpoint , &sz ) ; - if ( size > (int)sz ) - size = sz ; - res = OTRcv( m_endpoint , buffer , size , &flags ) ; - if ( res < 0 ) - { - return -1 ; - } - - // we simulate another read event if there are still bytes - if ( m_takesEvents ) - { - OTByteCount sz = 0 ; - OTCountDataBytes( m_endpoint , &sz ) ; - if ( sz > 0 ) - { - m_detected |= GSOCK_INPUT_FLAG ; - (m_cbacks[GSOCK_INPUT])(this, GSOCK_INPUT, m_data[GSOCK_INPUT]); - } - } - return res ; -} - -int GSocket::Recv_Dgram(char *buffer, int size) -{ -// TODO - int ret = -1; -#if 0 - struct sockaddr from; - WX_SOCKLEN_T fromlen = sizeof(from); - GSocketError err; - - fromlen = sizeof(from); - - ret = recvfrom(m_endpoint, buffer, size, 0, &from, (WX_SOCKLEN_T *) &fromlen); - - if (ret == -1) - return -1; - - /* Translate a system address into a GSocket address */ - if (!m_peer) - { - m_peer = GAddress_new(); - if (!m_peer) - { - m_error = GSOCK_MEMERR; - return -1; - } - } - err = _GAddress_translate_from(m_peer, &from, fromlen); - if (err != GSOCK_NOERROR) - { - GAddress_destroy(m_peer); - m_peer = NULL; - m_error = err; - return -1; - } -#endif - return ret; -} - -int GSocket::Send_Stream(const char *buffer, int size) -{ - OTFlags flags = 0 ; - OTResult res ; - - res = OTSnd( m_endpoint , (void*) buffer , size , flags ) ; - return res ; -} - -int GSocket::Send_Dgram(const char *buffer, int size) -{ - int ret = -1 ; -// TODO -#if 0 - struct sockaddr *addr; - int len ; - GSocketError err; - - if (!m_peer) - { - m_error = GSOCK_INVADDR; - return -1; - } - - err = _GAddress_translate_to(m_peer, &addr, &len); - if (err != GSOCK_NOERROR) - { - m_error = err; - return -1; - } - - ret = sendto(m_endpoint, buffer, size, 0, addr, len); - - /* Frees memory allocated from _GAddress_translate_to */ - free(addr); -#endif - return ret; -} - -/* Compatibility functions for GSocket */ -GSocket *GSocket_new(void) -{ - GSocket *newsocket = new GSocket(); - if(newsocket->IsOk()) - return newsocket; - delete newsocket; - return NULL; -} - - -/* - * ------------------------------------------------------------------------- - * GAddress - * ------------------------------------------------------------------------- - */ - -/* CHECK_ADDRESS verifies that the current family is either GSOCK_NOFAMILY - * or GSOCK_*family*, and if it is GSOCK_NOFAMILY, it initalizes address - * to be a GSOCK_*family*. In other cases, it returns GSOCK_INVADDR. - */ -#define CHECK_ADDRESS(address, family, retval) \ -{ \ - if (address->m_family == GSOCK_NOFAMILY) \ - if (_GAddress_Init_##family(address) != GSOCK_NOERROR) \ - return address->m_error; \ - if (address->m_family != GSOCK_##family) \ - { \ - address->m_error = GSOCK_INVADDR; \ - return retval; \ - } \ -} - -GAddress *GAddress_new() -{ - GAddress *address; - - if ((address = (GAddress *) malloc(sizeof(GAddress))) == NULL) - return NULL; - - address->m_family = GSOCK_NOFAMILY; - address->m_host = INADDR_NONE ; - address->m_port = 0 ; - - return address; -} - -GAddress *GAddress_copy(GAddress *address) -{ - GAddress *addr2; - - assert(address != NULL); - - if ((addr2 = (GAddress *) malloc(sizeof(GAddress))) == NULL) - return NULL; - - memcpy(addr2, address, sizeof(GAddress)); - return addr2; -} - -void GAddress_destroy(GAddress *address) -{ - assert(address != NULL); - - free(address); -} - -void GAddress_SetFamily(GAddress *address, GAddressType type) -{ - assert(address != NULL); - - address->m_family = type; -} - -GAddressType GAddress_GetFamily(GAddress *address) -{ - assert(address != NULL); - - return address->m_family; -} - -GSocketError _GAddress_translate_from(GAddress *address, - InetAddress *addr) -{ - switch (addr->fAddressType) - { - case AF_INET: - address->m_family = GSOCK_INET; - break; -#ifdef AF_INET6 - case AF_INET6: - address->m_family = GSOCK_INET6; - break; -#endif - default: - { - address->m_error = GSOCK_INVOP; - return GSOCK_INVOP; - } - } - address->m_host = addr->fHost ; - address->m_port = addr->fPort ; - return GSOCK_NOERROR; -} - -GSocketError _GAddress_translate_to(GAddress *address, - InetAddress *addr) -{ - if ( !GSocket_Verify_Inited() ) - return GSOCK_IOERR ; - memset(addr, 0 , sizeof(struct InetAddress)); - OTInitInetAddress( addr , address->m_port , address->m_host ) ; - return GSOCK_NOERROR; -} - -/* - * ------------------------------------------------------------------------- - * Internet address family - * ------------------------------------------------------------------------- - */ - -GSocketError _GAddress_Init_INET(GAddress *address) -{ - address->m_family = GSOCK_INET; - address->m_host = kOTAnyInetAddress ; - - return GSOCK_NOERROR; -} - -GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname) -{ - InetHostInfo hinfo ; - OSStatus ret ; - - if ( !GSocket_Verify_Inited() ) - return GSOCK_IOERR ; - - assert(address != NULL); - - CHECK_ADDRESS(address, INET, GSOCK_INVADDR); - ret = OTInetStringToAddress( gInetSvcRef , (char*) hostname , &hinfo ) ; - if ( ret != kOTNoError ) - { - address->m_host = INADDR_NONE ; - address->m_error = GSOCK_NOHOST; - return GSOCK_NOHOST; - } - address->m_host = hinfo.addrs[0] ; - return GSOCK_NOERROR; -} - -GSocketError GAddress_INET_SetBroadcastAddress(GAddress *address) -{ - return GAddress_INET_SetHostAddress(address, INADDR_BROADCAST); -} - -GSocketError GAddress_INET_SetAnyAddress(GAddress *address) -{ - return GAddress_INET_SetHostAddress(address, INADDR_ANY); -} - -GSocketError GAddress_INET_SetHostAddress(GAddress *address, - unsigned long hostaddr) -{ - assert(address != NULL); - - CHECK_ADDRESS(address, INET, GSOCK_INVADDR); - - address->m_host = htonl(hostaddr) ; - - return GSOCK_NOERROR; -} - -struct service_entry -{ - const char * name ; - unsigned short port ; - const char * protocol ; -} ; -typedef struct service_entry service_entry ; - -service_entry gServices[] = -{ - { "http" , 80 , "tcp" } -} ; - -GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port, - const char *protocol) -{ - size_t i ; - - assert(address != NULL); - CHECK_ADDRESS(address, INET, GSOCK_INVADDR); - - if (!port) - { - address->m_error = GSOCK_INVPORT; - return GSOCK_INVPORT; - } - for ( i = 0 ; i < sizeof( gServices) / sizeof( service_entry ) ; ++i ) - { - if ( strcmp( port , gServices[i].name ) == 0 ) - { - if ( protocol == NULL || strcmp( protocol , gServices[i].protocol ) ) - { - address->m_port = gServices[i].port ; - return GSOCK_NOERROR; - } - } - } - - if (isdigit(port[0])) - { - address->m_port = atoi(port); - return GSOCK_NOERROR; - } - - address->m_error = GSOCK_INVPORT; - return GSOCK_INVPORT; -} - -GSocketError GAddress_INET_SetPort(GAddress *address, unsigned short port) -{ - assert(address != NULL); - CHECK_ADDRESS(address, INET, GSOCK_INVADDR); - address->m_port = port ; - - return GSOCK_NOERROR; -} - -GSocketError GAddress_INET_GetHostName(GAddress *address, char *hostname, size_t sbuf) -{ - InetDomainName name ; - if ( !GSocket_Verify_Inited() ) - return GSOCK_IOERR ; - - assert(address != NULL); - CHECK_ADDRESS(address, INET, GSOCK_INVADDR); - - OTInetAddressToName( gInetSvcRef , address->m_host , name ) ; - strncpy( hostname , name , sbuf ) ; - return GSOCK_NOERROR; -} - -unsigned long GAddress_INET_GetHostAddress(GAddress *address) -{ - assert(address != NULL); - CHECK_ADDRESS(address, INET, 0); - - return ntohl(address->m_host); -} - -unsigned short GAddress_INET_GetPort(GAddress *address) -{ - assert(address != NULL); - CHECK_ADDRESS(address, INET, 0); - - return address->m_port; -} - -void GSocket::Enable_Events() -{ - if ( m_takesEvents ) - return ; - - { - OTResult state ; - m_takesEvents = true ; - state = OTGetEndpointState(m_endpoint); - - { - OTByteCount sz = 0 ; - OTCountDataBytes( m_endpoint , &sz ) ; - if ( state == T_INCON || sz > 0 ) - { - m_detected |= GSOCK_INPUT_FLAG ; - (m_cbacks[GSOCK_INPUT])(this, GSOCK_INPUT, m_data[GSOCK_INPUT]); - } - } - { - if ( state == T_DATAXFER || state == T_INREL ) - { - m_detected |=GSOCK_OUTPUT_FLAG ; - (m_cbacks[GSOCK_OUTPUT])(this, GSOCK_OUTPUT, m_data[GSOCK_OUTPUT]); - } - } - } -} - -void GSocket::Disable_Events() -{ - m_takesEvents = false ; -} - -/* _GSocket_Input_Timeout: - * For blocking sockets, wait until data is available or - * until timeout ellapses. - */ -GSocketError GSocket::Input_Timeout() -{ - if ( !m_non_blocking ) - { - UnsignedWide now , start ; - bool formerTakesEvents = m_takesEvents ; - Microseconds(&start); - now = start ; - m_takesEvents = false ; - - while( (now.hi * 4294967296.0 + now.lo) - (start.hi * 4294967296.0 + start.lo) < m_timeout * 1000.0 ) - { - OTResult state ; - OTByteCount sz = 0 ; - state = OTGetEndpointState(m_endpoint); - - OTCountDataBytes( m_endpoint , &sz ) ; - if ( state == T_INCON || sz > 0 ) - { - m_takesEvents = formerTakesEvents ; - return GSOCK_NOERROR; - } - Microseconds(&now); - } - m_takesEvents = formerTakesEvents ; - m_error = GSOCK_TIMEDOUT; - return GSOCK_TIMEDOUT; - } - return GSOCK_NOERROR; -} - -/* _GSocket_Output_Timeout: - * For blocking sockets, wait until data can be sent without - * blocking or until timeout ellapses. - */ -GSocketError GSocket::Output_Timeout() -{ - if ( !m_non_blocking ) - { - UnsignedWide now , start ; - bool formerTakesEvents = m_takesEvents ; - Microseconds(&start); - now = start ; - m_takesEvents = false ; - - while( (now.hi * 4294967296.0 + now.lo) - (start.hi * 4294967296.0 + start.lo) < m_timeout * 1000.0 ) - { - OTResult state ; - state = OTGetEndpointState(m_endpoint); - - if ( state == T_DATAXFER || state == T_INREL ) - { - m_takesEvents = formerTakesEvents ; - return GSOCK_NOERROR; - } - Microseconds(&now); - } - m_takesEvents = formerTakesEvents ; - m_error = GSOCK_TIMEDOUT; - return GSOCK_TIMEDOUT; - } - return GSOCK_NOERROR; -} - -/* GSOCK_INPUT: - * There is data to be read in the input buffer. If, after a read - * operation, there is still data available, the callback function will - * be called again. - * GSOCK_OUTPUT: - * The socket is available for writing. That is, the next write call - * won't block. This event is generated only once, when the connection is - * first established, and then only if a call failed with GSOCK_WOULDBLOCK, - * when the output buffer empties again. This means that the app should - * assume that it can write since the first OUTPUT event, and no more - * OUTPUT events will be generated unless an error occurs. - * GSOCK_CONNECTION: - * Connection successfully established, for client sockets, or incoming - * client connection, for server sockets. Wait for this event (also watch - * out for GSOCK_LOST) after you issue a nonblocking GSocket_Connect() call. - * GSOCK_LOST: - * The connection is lost (or a connection request failed); this could - * be due to a failure, or due to the peer closing it gracefully. - */ - -void _GSocket_Internal_Proc(unsigned long e , void* d ) -{ - GSocket *socket = (GSocket*) d ; - - if ( !socket ) - return ; - - OTEventCode ev = (OTEventCode) e ; - GSocketEvent event; - GSocketEvent event2; - GSocketCallback cback; - char *data; - GSocketCallback cback2; - char *data2; - - event = GSOCK_MAX_EVENT ; - event2 = GSOCK_MAX_EVENT ; - cback = NULL; - data = NULL; - cback2 = NULL; - data2 = NULL; - - /* Check that the socket still exists (it has not been - * destroyed) and for safety, check that the m_endpoint field - * is what we expect it to be. - */ - if ( /* (socket != NULL) && */ (socket->m_takesEvents)) - { - switch (ev) - { - case T_LISTEN : - event = GSOCK_CONNECTION ; - break ; - case T_CONNECT : - event = GSOCK_CONNECTION ; - event2 = GSOCK_OUTPUT ; - { - TCall retCall; - - retCall.addr.buf = NULL; - retCall.addr.maxlen = 0; - retCall.opt.buf = NULL; - retCall.opt.maxlen = 0; - retCall.udata.buf = NULL; - retCall.udata.maxlen = 0; - OTRcvConnect( socket->m_endpoint , &retCall ) ; - } - break ; - case T_DISCONNECT : - event = GSOCK_LOST ; - break ; - case T_GODATA : - case T_GOEXDATA : - event = GSOCK_OUTPUT ; - break ; - case T_DATA : - event = GSOCK_INPUT ; - break ; - case T_EXDATA : - event = GSOCK_INPUT ; - break ; - } - if (event != GSOCK_MAX_EVENT) - { - cback = socket->m_cbacks[event]; - data = socket->m_data[event]; - - if (event == GSOCK_LOST) - socket->m_detected = GSOCK_LOST_FLAG; - else - socket->m_detected |= (1 << event); - } - if (event2 != GSOCK_MAX_EVENT) - { - cback2 = socket->m_cbacks[event2]; - data2 = socket->m_data[event2]; - - if (event2 == GSOCK_LOST) - socket->m_detected = GSOCK_LOST_FLAG; - else - socket->m_detected |= (1 << event2); - } - } - - /* OK, we can now leave the critical section because we have - * already obtained the callback address (we make no further - * accesses to socket->whatever). However, the app should - * be prepared to handle events from a socket that has just - * been closed! - */ - - if (cback != NULL) - (cback)(socket, event, data); - if (cback2 != NULL) - (cback2)(socket, event2, data2); - -} - -/* Hack added for Mac OS X */ -GSocketError GAddress_UNIX_GetPath(GAddress *addr, char *path, size_t buf) -{ - return GSOCK_INVADDR; -} - -GSocketError GAddress_UNIX_SetPath(GAddress *addr, const char *path) -{ - return GSOCK_INVADDR; -} - -#endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */ diff --git a/src/mac/carbon/mpthread.cpp b/src/mac/carbon/mpthread.cpp deleted file mode 100644 index 30bb2a0087..0000000000 --- a/src/mac/carbon/mpthread.cpp +++ /dev/null @@ -1,1559 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/mac/carbon/mpthread.cpp -// Purpose: wxThread Implementation -// Author: Original from Wolfram Gloger/Guilhem Lavaux/Vadim Zeitlin -// Modified by: Aj Lavin, Stefan Csomor -// Created: 04/22/98 -// RCS-ID: $Id$ -// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998), -// Vadim Zeitlin (1999) , Stefan Csomor (2000) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#if wxUSE_THREADS - -#ifndef WX_PRECOMP - #include "wx/wx.h" - #include "wx/module.h" -#endif - -#include "wx/thread.h" - -#ifdef __WXMAC__ -#if TARGET_API_MAC_OSX -#include -#else -#include -#include -#endif -#include "wx/mac/uma.h" -#endif - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// the possible states of the thread ("=>" shows all possible transitions from -// this state) -enum wxThreadState -{ - STATE_NEW, // didn't start execution yet (=> RUNNING) - STATE_RUNNING, // thread is running (=> PAUSED, CANCELED) - STATE_PAUSED, // thread is temporarily suspended (=> RUNNING) - STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED) - STATE_EXITED // thread is terminating -}; - -// ---------------------------------------------------------------------------- -// this module globals -// ---------------------------------------------------------------------------- - - -// the task ID of the main thread -static wxThreadIdType gs_idMainThread = kInvalidID; - -// this is the Per-Task Storage for the pointer to the appropriate wxThread -TaskStorageIndex gs_tlsForWXThread = 0 ; - -// if it's false, some secondary thread is holding the GUI lock -static bool gs_bGuiOwnedByMainThread = true; - -// critical section which controls access to all GUI functions: any secondary -// thread (i.e. except the main one) must enter this crit section before doing -// any GUI calls -static wxCriticalSection *gs_critsectGui = NULL; - -// critical section which protects gs_nWaitingForGui variable -static wxCriticalSection *gs_critsectWaitingForGui = NULL; - -// number of threads waiting for GUI in wxMutexGuiEnter() -static size_t gs_nWaitingForGui = 0; - -// overall number of threads, needed for determining the sleep value of the main -// event loop -size_t g_numberOfThreads = 0; - - - -#if wxUSE_GUI - -MPCriticalRegionID gs_guiCritical = kInvalidID; - -#endif - -// ============================================================================ -// MacOS implementation of thread classes -// ============================================================================ - -/* - Notes : - - The implementation is very close to the phtreads implementation, the reason for - using MPServices is the fact that these are also available under OS 9. Thus allowing - for one common API for all current builds. - - As soon as wxThreads are on a 64 bit address space, the TLS must be extended - to use two indices one for each 32 bit part as the MP implementation is limited - to longs. - - I have two implementations for mutexes : - version A based on a binary semaphore, problem - not reentrant, version B based - on a critical region, allows for reentrancy, performance implications not - yet tested - - The same for condition internal, one implementation by Aj Lavin and the other one - copied from the thrimpl.cpp which I assume has been more broadly tested, I've just - replaced the interlock increment with the appropriate PPC calls -*/ - -// ---------------------------------------------------------------------------- -// wxMutex implementation -// ---------------------------------------------------------------------------- - -static bool wxMacMPThreadsInitVerify() -{ - static bool hasThreadManager = false ; - if ( !hasThreadManager ) - hasThreadManager = MPLibraryIsLoaded(); - - if ( !hasThreadManager ) - { - wxMessageBox( wxT("Error") , wxT("MP Thread Support is not available on this System" ), wxOK ) ; - return false ; - } - return true ; -} - -#if 0 - -class wxMutexInternal -{ -public: - wxMutexInternal(wxMutexType mutexType) ; - ~wxMutexInternal() ; - bool IsOk() const { return m_isOk; } - - wxMutexError Lock() ; - wxMutexError TryLock() ; - wxMutexError Unlock(); -private: - MPSemaphoreID m_semaphore; - bool m_isOk ; -}; - -wxMutexInternal::wxMutexInternal(wxMutexType mutexType ) -{ - wxMacMPThreadsInitVerify() ; - - m_isOk = false ; - m_semaphore = kInvalidID ; - - OSStatus err = noErr ; - switch( mutexType ) - { - case wxMUTEX_DEFAULT : - { - verify_noerr( MPCreateBinarySemaphore( & m_semaphore) ); - m_isOk = ( m_semaphore != kInvalidID ) ; - } - break ; - case wxMUTEX_RECURSIVE : - wxFAIL_MSG(wxT("Recursive Mutex not supported yet") ) ; - break ; - default : - wxFAIL_MSG(wxT("Unknown mutex type") ) ; - break ; - } -} - -wxMutexInternal::~wxMutexInternal() -{ - if ( m_semaphore != kInvalidID ) - MPDeleteSemaphore( m_semaphore); -} - -wxMutexError wxMutexInternal::Lock() -{ - wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ; - OSStatus err = MPWaitOnSemaphore( m_semaphore, kDurationForever); - if ( err) - { - wxLogSysError(wxT("Could not lock mutex")); - return wxMUTEX_MISC_ERROR; - } - - return wxMUTEX_NO_ERROR; -} - -wxMutexError wxMutexInternal::TryLock() -{ - wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ; - OSStatus err = MPWaitOnSemaphore( m_semaphore, kDurationImmediate); - if ( err) - { - if ( err == kMPTimeoutErr) - { - return wxMUTEX_BUSY; - } - wxLogSysError(wxT("Could not try lock mutex")); - return wxMUTEX_MISC_ERROR; - } - - return wxMUTEX_NO_ERROR; -} - -wxMutexError wxMutexInternal::Unlock() -{ - wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ; - OSStatus err = MPSignalSemaphore( m_semaphore); - if ( err) - { - wxLogSysError(_("Could not unlock mutex")); - return wxMUTEX_MISC_ERROR; - } - - return wxMUTEX_NO_ERROR; -} - -#else - -class wxMutexInternal -{ -public: - wxMutexInternal(wxMutexType mutexType) ; - ~wxMutexInternal() ; - bool IsOk() const { return m_isOk; } - - wxMutexError Lock() ; - wxMutexError TryLock() ; - wxMutexError Unlock(); -private: - MPCriticalRegionID m_critRegion ; - bool m_isOk ; -}; - -wxMutexInternal::wxMutexInternal(wxMutexType mutexType ) -{ - wxMacMPThreadsInitVerify() ; - m_isOk = false ; - m_critRegion = kInvalidID ; - - verify_noerr( MPCreateCriticalRegion( & m_critRegion) ); - m_isOk = ( m_critRegion != kInvalidID ) ; - - if ( !IsOk() ) - wxFAIL_MSG(wxT("Error when creating mutex") ) ; -} - -wxMutexInternal::~wxMutexInternal() -{ - if ( m_critRegion != kInvalidID ) - MPDeleteCriticalRegion( m_critRegion); -} - -wxMutexError wxMutexInternal::Lock() -{ - wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ; - OSStatus err = MPEnterCriticalRegion( m_critRegion, kDurationForever); - if ( err) - { - wxLogSysError(wxT("Could not lock mutex")); - return wxMUTEX_MISC_ERROR; - } - - return wxMUTEX_NO_ERROR; -} - -wxMutexError wxMutexInternal::TryLock() -{ - wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ; - OSStatus err = MPEnterCriticalRegion( m_critRegion, kDurationImmediate); - if ( err) - { - if ( err == kMPTimeoutErr) - { - return wxMUTEX_BUSY; - } - wxLogSysError(wxT("Could not try lock mutex")); - return wxMUTEX_MISC_ERROR; - } - - return wxMUTEX_NO_ERROR; -} - -wxMutexError wxMutexInternal::Unlock() -{ - wxCHECK_MSG( m_isOk , wxMUTEX_MISC_ERROR , wxT("Invalid Mutex") ) ; - OSStatus err = MPExitCriticalRegion( m_critRegion); - if ( err) - { - wxLogSysError(_("Could not unlock mutex")); - return wxMUTEX_MISC_ERROR; - } - - return wxMUTEX_NO_ERROR; -} - -#endif - -// -------------------------------------------------------------------------- -// wxSemaphore -// -------------------------------------------------------------------------- - -class wxSemaphoreInternal -{ -public: - wxSemaphoreInternal(int initialcount, int maxcount); - ~wxSemaphoreInternal(); - - bool IsOk() const { return m_isOk; } - - wxSemaError WaitTimeout(unsigned long milliseconds); - - wxSemaError Wait() { return WaitTimeout( kDurationForever); } - - wxSemaError TryWait() - { - wxSemaError err = WaitTimeout(kDurationImmediate); - if ( err == wxSEMA_TIMEOUT ) - err = wxSEMA_BUSY ; - return err ; - } - wxSemaError Post(); - -private: - MPSemaphoreID m_semaphore; - bool m_isOk ; -}; - -wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount) -{ - wxMacMPThreadsInitVerify() ; - m_isOk = false ; - m_semaphore = kInvalidID ; - if ( maxcount == 0 ) - { - // make it practically infinite - maxcount = INT_MAX; - } - verify_noerr( MPCreateSemaphore( maxcount, initialcount, & m_semaphore) ); - m_isOk = ( m_semaphore != kInvalidID ) ; - - if ( !IsOk() ) - wxFAIL_MSG(wxT("Error when creating semaphore") ) ; -} - -wxSemaphoreInternal::~wxSemaphoreInternal() -{ - if( m_semaphore != kInvalidID ) - MPDeleteSemaphore( m_semaphore); -} - -wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds) -{ - OSStatus err = MPWaitOnSemaphore( m_semaphore, milliseconds); - if ( err) - { - if ( err == kMPTimeoutErr) - { - return wxSEMA_TIMEOUT; - } - return wxSEMA_MISC_ERROR; - } - return wxSEMA_NO_ERROR; -} - -wxSemaError wxSemaphoreInternal::Post() -{ - OSStatus err = MPSignalSemaphore( m_semaphore); - if ( err) - { - return wxSEMA_MISC_ERROR; - } - return wxSEMA_NO_ERROR; -} - -// ---------------------------------------------------------------------------- -// wxCondition implementation -// ---------------------------------------------------------------------------- - -#if 0 - -class wxConditionInternal -{ -public: - - wxConditionInternal(wxMutex& mutex) - : m_mutex( mutex), - m_semaphore( 0, 1), - m_gate( 1, 1) - { - m_waiters = 0; - m_signals = 0; - m_canceled = 0; - } - - ~wxConditionInternal() - { - } - - bool IsOk() const { return m_mutex.IsOk() ; } - - wxCondError Wait() - { - return WaitTimeout( kDurationForever); - } - - wxCondError WaitTimeout(unsigned long msectimeout); - - wxCondError Signal() - { - return DoSignal( false); - } - - wxCondError Broadcast() - { - return DoSignal( true); - } - -private: - - wxCondError DoSignal( bool signalAll); - - wxMutex& m_mutex; - wxSemaphoreInternal m_semaphore; // Signals the waiting threads. - wxSemaphoreInternal m_gate; - wxCriticalSection m_varSection; - size_t m_waiters; // Number of threads waiting for a signal. - size_t m_signals; // Number of signals to send. - size_t m_canceled; // Number of canceled waiters in m_waiters. -}; - - -wxCondError wxConditionInternal::WaitTimeout(unsigned long msectimeout) -{ - m_gate.Wait(); - if ( ++ m_waiters == INT_MAX) - { - m_varSection.Enter(); - m_waiters -= m_canceled; - m_signals -= m_canceled; - m_canceled = 0; - m_varSection.Leave(); - } - m_gate.Post(); - - m_mutex.Unlock(); - - wxSemaError err = m_semaphore.WaitTimeout( msectimeout); - wxASSERT( err == wxSEMA_NO_ERROR || err == wxSEMA_TIMEOUT); - - m_varSection.Enter(); - if ( err != wxSEMA_NO_ERROR) - { - if ( m_signals > m_canceled) - { - // A signal is being sent after we timed out. - - if ( m_waiters == m_signals) - { - // There are no excess waiters to catch the signal, so - // we must throw it away. - - wxSemaError err2 = m_semaphore.Wait(); - if ( err2 != wxSEMA_NO_ERROR) - { - wxLogSysError(_("Error while waiting on semaphore")); - } - wxASSERT( err2 == wxSEMA_NO_ERROR); - -- m_waiters; - if ( -- m_signals == m_canceled) - { - // This was the last signal. open the gate. - wxASSERT( m_waiters == m_canceled); - m_gate.Post(); - } - } - else - { - // There are excess waiters to catch the signal, leave - // it be. - -- m_waiters; - } - } - else - { - // No signals is being sent. - // The gate may be open or closed, so we can't touch m_waiters. - ++ m_canceled; - ++ m_signals; - } - } - else - { - // We caught a signal. - wxASSERT( m_signals > m_canceled); - -- m_waiters; - if ( -- m_signals == m_canceled) - { - // This was the last signal. open the gate. - wxASSERT( m_waiters == m_canceled); - m_gate.Post(); - } - } - m_varSection.Leave(); - - m_mutex.Lock(); - - if ( err) - { - return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR; - } - - return wxCOND_NO_ERROR; -} - - -wxCondError wxConditionInternal::DoSignal( bool signalAll) -{ - m_gate.Wait(); - m_varSection.Enter(); - - wxASSERT( m_signals == m_canceled); - - if ( m_waiters == m_canceled) - { - m_varSection.Leave(); - m_gate.Post(); - return wxCOND_NO_ERROR; - } - - if ( m_canceled > 0) - { - m_waiters -= m_canceled; - m_signals = 0; - m_canceled = 0; - } - - m_signals = signalAll ? m_waiters : 1; - size_t n = m_signals; - - m_varSection.Leave(); - - // Let the waiters inherit the gate lock. - - do - { - wxSemaError err = m_semaphore.Post(); - wxASSERT( err == wxSEMA_NO_ERROR); - } while ( -- n); - - return wxCOND_NO_ERROR; -} - -#else -class wxConditionInternal -{ -public: - wxConditionInternal(wxMutex& mutex); - - bool IsOk() const { return m_mutex.IsOk() && m_semaphore.IsOk(); } - - wxCondError Wait(); - wxCondError WaitTimeout(unsigned long milliseconds); - - wxCondError Signal(); - wxCondError Broadcast(); - -private: - // the number of threads currently waiting for this condition - SInt32 m_numWaiters; - - // the critical section protecting m_numWaiters - wxCriticalSection m_csWaiters; - - wxMutex& m_mutex; - wxSemaphore m_semaphore; - - DECLARE_NO_COPY_CLASS(wxConditionInternal) -}; - -wxConditionInternal::wxConditionInternal(wxMutex& mutex) - : m_mutex(mutex) -{ - // another thread can't access it until we return from ctor, so no need to - // protect access to m_numWaiters here - m_numWaiters = 0; -} - -wxCondError wxConditionInternal::Wait() -{ - // increment the number of waiters - IncrementAtomic(&m_numWaiters); - - m_mutex.Unlock(); - - // a potential race condition can occur here - // - // after a thread increments nwaiters, and unlocks the mutex and before the - // semaphore.Wait() is called, if another thread can cause a signal to be - // generated - // - // this race condition is handled by using a semaphore and incrementing the - // semaphore only if 'nwaiters' is greater that zero since the semaphore, - // can 'remember' signals the race condition will not occur - - // wait ( if necessary ) and decrement semaphore - wxSemaError err = m_semaphore.Wait(); - m_mutex.Lock(); - - return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR; -} - -wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds) -{ - IncrementAtomic(&m_numWaiters); - - m_mutex.Unlock(); - - // a race condition can occur at this point in the code - // - // please see the comments in Wait(), for details - - wxSemaError err = m_semaphore.WaitTimeout(milliseconds); - - if ( err == wxSEMA_BUSY ) - { - // another potential race condition exists here it is caused when a - // 'waiting' thread timesout, and returns from WaitForSingleObject, but - // has not yet decremented 'nwaiters'. - // - // at this point if another thread calls signal() then the semaphore - // will be incremented, but the waiting thread will miss it. - // - // to handle this particular case, the waiting thread calls - // WaitForSingleObject again with a timeout of 0, after locking - // 'nwaiters_mutex'. this call does not block because of the zero - // timeout, but will allow the waiting thread to catch the missed - // signals. - wxCriticalSectionLocker lock(m_csWaiters); - - err = m_semaphore.WaitTimeout(0); - - if ( err != wxSEMA_NO_ERROR ) - { - m_numWaiters--; - } - } - - m_mutex.Lock(); - - return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR; -} - -wxCondError wxConditionInternal::Signal() -{ - wxCriticalSectionLocker lock(m_csWaiters); - - if ( m_numWaiters > 0 ) - { - // increment the semaphore by 1 - if ( m_semaphore.Post() != wxSEMA_NO_ERROR ) - return wxCOND_MISC_ERROR; - - m_numWaiters--; - } - - return wxCOND_NO_ERROR; -} - -wxCondError wxConditionInternal::Broadcast() -{ - wxCriticalSectionLocker lock(m_csWaiters); - - while ( m_numWaiters > 0 ) - { - if ( m_semaphore.Post() != wxSEMA_NO_ERROR ) - return wxCOND_MISC_ERROR; - - m_numWaiters--; - } - - return wxCOND_NO_ERROR; -} -#endif - -// ---------------------------------------------------------------------------- -// wxCriticalSection implementation -// ---------------------------------------------------------------------------- - -// XXX currently implemented as mutex in headers. Change to critical section. - -// ---------------------------------------------------------------------------- -// wxThread implementation -// ---------------------------------------------------------------------------- - -// wxThreadInternal class -// ---------------------- - -class wxThreadInternal -{ -public: - wxThreadInternal() - { - m_tid = kInvalidID; - m_state = STATE_NEW; - m_prio = WXTHREAD_DEFAULT_PRIORITY; - m_notifyQueueId = kInvalidID; - m_exitcode = 0; - m_cancelled = false ; - - // set to true only when the thread starts waiting on m_semSuspend - m_isPaused = false; - - // defaults for joinable threads - m_shouldBeJoined = true; - m_isDetached = false; - } - ~wxThreadInternal() - { - if ( m_notifyQueueId) - { - MPDeleteQueue( m_notifyQueueId); - m_notifyQueueId = kInvalidID ; - } - } - - // thread function - static OSStatus MacThreadStart(void* arg); - - // create a new (suspended) thread (for the given thread object) - bool Create(wxThread *thread, unsigned int stackSize); - - // thread actions - // start the thread - wxThreadError Run(); - // unblock the thread allowing it to run - void SignalRun() { m_semRun.Post(); } - // ask the thread to terminate - void Wait(); - // go to sleep until Resume() is called - void Pause(); - // resume the thread - void Resume(); - - // accessors - // priority - int GetPriority() const { return m_prio; } - void SetPriority(int prio) ; - // state - wxThreadState GetState() const { return m_state; } - void SetState(wxThreadState state) { m_state = state; } - - // Get the ID of this thread's underlying MP Services task. - MPTaskID GetId() const { return m_tid; } - - void SetCancelFlag() { m_cancelled = true; } - bool WasCancelled() const { return m_cancelled; } - // exit code - void SetExitCode(wxThread::ExitCode exitcode) { m_exitcode = exitcode; } - wxThread::ExitCode GetExitCode() const { return m_exitcode; } - - // the pause flag - void SetReallyPaused(bool paused) { m_isPaused = paused; } - bool IsReallyPaused() const { return m_isPaused; } - - // tell the thread that it is a detached one - void Detach() - { - wxCriticalSectionLocker lock(m_csJoinFlag); - - m_shouldBeJoined = false; - m_isDetached = true; - } - -private: - // the thread we're associated with - wxThread * m_thread; - - MPTaskID m_tid; // thread id - MPQueueID m_notifyQueueId; // its notification queue - - wxThreadState m_state; // see wxThreadState enum - int m_prio; // in wxWidgets units: from 0 to 100 - - // this flag is set when the thread should terminate - bool m_cancelled; - - // this flag is set when the thread is blocking on m_semSuspend - bool m_isPaused; - - // the thread exit code - only used for joinable (!detached) threads and - // is only valid after the thread termination - wxThread::ExitCode m_exitcode; - - // many threads may call Wait(), but only one of them should call - // pthread_join(), so we have to keep track of this - wxCriticalSection m_csJoinFlag; - bool m_shouldBeJoined; - bool m_isDetached; - - // this semaphore is posted by Run() and the threads Entry() is not - // called before it is done - wxSemaphore m_semRun; - - // this one is signaled when the thread should resume after having been - // Pause()d - wxSemaphore m_semSuspend; -}; - -OSStatus wxThreadInternal::MacThreadStart(void *parameter) -{ - wxThread* thread = (wxThread*) parameter ; - wxThreadInternal *pthread = thread->m_internal; - - // add to TLS so that This() will work - verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread , (long) thread ) ) ; - - // have to declare this before pthread_cleanup_push() which defines a - // block! - bool dontRunAtAll; - - // wait for the semaphore to be posted from Run() - pthread->m_semRun.Wait(); - - // test whether we should run the run at all - may be it was deleted - // before it started to Run()? - { - wxCriticalSectionLocker lock(thread->m_critsect); - - dontRunAtAll = pthread->GetState() == STATE_NEW && - pthread->WasCancelled(); - } - - if ( !dontRunAtAll ) - { - pthread->m_exitcode = thread->Entry(); - - { - wxCriticalSectionLocker lock(thread->m_critsect); - pthread->SetState(STATE_EXITED); - } - } - - if ( dontRunAtAll ) - { - if ( pthread->m_isDetached ) - delete thread; - - return -1 ; - } - else - { - // on mac for the running code the correct thread termination is to - // return - - // terminate the thread - thread->Exit(pthread->m_exitcode); - - return (OSStatus) NULL ; // pthread->m_exitcode; - } -} - -bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize) -{ - wxMacMPThreadsInitVerify() ; - wxASSERT_MSG( m_state == STATE_NEW && !m_tid, - _T("Create()ing thread twice?") ); - - OSStatus err = noErr ; - m_thread = thread; - - if ( m_notifyQueueId == kInvalidID ) - { - OSStatus err = MPCreateQueue( & m_notifyQueueId); - if( err) - { - wxLogSysError(_("Cant create the thread event queue")); - return false; - } - } - - m_state = STATE_NEW; - - err = MPCreateTask( MacThreadStart, - (void*) m_thread, - stackSize, - m_notifyQueueId, - &m_exitcode, - 0, - 0, - &m_tid); - - if ( err) - { - wxLogSysError(_("Can't create thread")); - return false; - } - - if ( m_prio != WXTHREAD_DEFAULT_PRIORITY ) - { - SetPriority(m_prio); - } - - return true; -} - -void wxThreadInternal::SetPriority( int priority) -{ - m_prio = priority; - - if ( m_tid) - { - // Mac priorities range from 1 to 10,000, with a default of 100. - // wxWidgets priorities range from 0 to 100 with a default of 50. - // We can map wxWidgets to Mac priorities easily by assuming - // the former uses a logarithmic scale. - const unsigned int macPriority = ( int)( exp( priority / 25.0 * log( 10.0)) + 0.5); - - MPSetTaskWeight( m_tid, macPriority); - } -} - -wxThreadError wxThreadInternal::Run() -{ - wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING, - wxT("thread may only be started once after Create()") ); - - SetState(STATE_RUNNING); - - // wake up threads waiting for our start - SignalRun(); - - return wxTHREAD_NO_ERROR; -} - -void wxThreadInternal::Wait() -{ - wxCHECK_RET( !m_isDetached, _T("can't wait for a detached thread") ); - - // if the thread we're waiting for is waiting for the GUI mutex, we will - // deadlock so make sure we release it temporarily - if ( wxThread::IsMain() ) - wxMutexGuiLeave(); - - { - wxCriticalSectionLocker lock(m_csJoinFlag); - - if ( m_shouldBeJoined ) - { - void * param1; - void * param2; - void * rc; - - OSStatus err = MPWaitOnQueue ( m_notifyQueueId, - & param1, - & param2, - & rc, - kDurationForever); - if ( err) - { - wxLogSysError( _( "Cannot wait for thread termination.")); - rc = (void*) -1; - } - - // actually param1 would be the address of m_exitcode - // but we don't need this here - m_exitcode = rc; - - m_shouldBeJoined = false; - } - } - - // reacquire GUI mutex - if ( wxThread::IsMain() ) - wxMutexGuiEnter(); -} - -void wxThreadInternal::Pause() -{ - // the state is set from the thread which pauses us first, this function - // is called later so the state should have been already set - wxCHECK_RET( m_state == STATE_PAUSED, - wxT("thread must first be paused with wxThread::Pause().") ); - - // wait until the semaphore is Post()ed from Resume() - m_semSuspend.Wait(); -} - -void wxThreadInternal::Resume() -{ - wxCHECK_RET( m_state == STATE_PAUSED, - wxT("can't resume thread which is not suspended.") ); - - // the thread might be not actually paused yet - if there were no call to - // TestDestroy() since the last call to Pause() for example - if ( IsReallyPaused() ) - { - // wake up Pause() - m_semSuspend.Post(); - - // reset the flag - SetReallyPaused(FALSE); - } - - SetState(STATE_RUNNING); -} - -// static functions -// ---------------- - -wxThread *wxThread::This() -{ - wxThread* thr = (wxThread*) MPGetTaskStorageValue( gs_tlsForWXThread ) ; - return thr; -} - -bool wxThread::IsMain() -{ - return GetCurrentId() == gs_idMainThread; -} - -#ifdef Yield -#undef Yield -#endif - -void wxThread::Yield() -{ -#if TARGET_API_MAC_OSX - CFRunLoopRunInMode( kCFRunLoopDefaultMode , 0 , true ) ; -#endif - MPYield(); -} - - -void wxThread::Sleep(unsigned long milliseconds) -{ - AbsoluteTime wakeup = AddDurationToAbsolute( milliseconds, UpTime()); - MPDelayUntil( & wakeup); -} - - -int wxThread::GetCPUCount() -{ - return MPProcessors(); -} - -unsigned long wxThread::GetCurrentId() -{ - return (unsigned long)MPCurrentTaskID(); -} - - -bool wxThread::SetConcurrency(size_t level) -{ - // Cannot be set in MacOS. - return false; -} - - -wxThread::wxThread(wxThreadKind kind) -{ - g_numberOfThreads++; - m_internal = new wxThreadInternal(); - - m_isDetached = (kind == wxTHREAD_DETACHED); -} - -wxThread::~wxThread() -{ - wxASSERT_MSG( g_numberOfThreads>0 , wxT("More threads deleted than created.") ) ; - g_numberOfThreads--; - -#ifdef __WXDEBUG__ - m_critsect.Enter(); - - // check that the thread either exited or couldn't be created - if ( m_internal->GetState() != STATE_EXITED && - m_internal->GetState() != STATE_NEW ) - { - wxLogDebug(_T("The thread %ld is being destroyed although it is still running! The application may crash."), GetId()); - } - - m_critsect.Leave(); -#endif // __WXDEBUG__ - - wxDELETE( m_internal ) ; -} - - -wxThreadError wxThread::Create(unsigned int stackSize) -{ - wxCriticalSectionLocker lock(m_critsect); - - if ( m_isDetached ) - { - m_internal->Detach() ; - } - if ( m_internal->Create(this, stackSize) == false ) - { - m_internal->SetState(STATE_EXITED); - return wxTHREAD_NO_RESOURCE; - } - - return wxTHREAD_NO_ERROR; -} - -wxThreadError wxThread::Run() -{ - wxCriticalSectionLocker lock(m_critsect); - - wxCHECK_MSG( m_internal->GetId(), wxTHREAD_MISC_ERROR, - wxT("must call wxThread::Create() first") ); - - return m_internal->Run(); -} - -// ----------------------------------------------------------------------------- -// pause/resume -// ----------------------------------------------------------------------------- - -wxThreadError wxThread::Pause() -{ - wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, - _T("a thread can't pause itself") ); - - wxCriticalSectionLocker lock(m_critsect); - - if ( m_internal->GetState() != STATE_RUNNING ) - { - wxLogDebug(wxT("Can't pause thread which is not running.")); - - return wxTHREAD_NOT_RUNNING; - } - - // just set a flag, the thread will be really paused only during the next - // call to TestDestroy() - m_internal->SetState(STATE_PAUSED); - - return wxTHREAD_NO_ERROR; -} - -wxThreadError wxThread::Resume() -{ - wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, - _T("a thread can't resume itself") ); - - wxCriticalSectionLocker lock(m_critsect); - - wxThreadState state = m_internal->GetState(); - - switch ( state ) - { - case STATE_PAUSED: - m_internal->Resume(); - return wxTHREAD_NO_ERROR; - case STATE_EXITED: - return wxTHREAD_NO_ERROR; - - default: - wxLogDebug(_T("Attempt to resume a thread which is not paused.")); - - return wxTHREAD_MISC_ERROR; - } -} - -// ----------------------------------------------------------------------------- -// exiting thread -// ----------------------------------------------------------------------------- - -wxThread::ExitCode wxThread::Wait() -{ - wxCHECK_MSG( This() != this, (ExitCode)-1, - _T("a thread can't wait for itself") ); - - wxCHECK_MSG( !m_isDetached, (ExitCode)-1, - _T("can't wait for detached thread") ); - - m_internal->Wait(); - - return m_internal->GetExitCode(); -} - -wxThreadError wxThread::Delete(ExitCode *rc) -{ - wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, - _T("a thread can't delete itself") ); - - bool isDetached = m_isDetached; - - m_critsect.Enter(); - wxThreadState state = m_internal->GetState(); - - // ask the thread to stop - m_internal->SetCancelFlag(); - - m_critsect.Leave(); - - switch ( state ) - { - case STATE_NEW: - // we need to wake up the thread so that PthreadStart() will - // terminate - right now it's blocking on run semaphore in - // PthreadStart() - m_internal->SignalRun(); - - // fall through - - case STATE_EXITED: - // nothing to do - break; - - case STATE_PAUSED: - // resume the thread first - m_internal->Resume(); - - // fall through - - default: - if ( !isDetached ) - { - // wait until the thread stops - m_internal->Wait(); - - if ( rc ) - { - // return the exit code of the thread - *rc = m_internal->GetExitCode(); - } - } - //else: can't wait for detached threads - } - - return wxTHREAD_NO_ERROR; -} - -wxThreadError wxThread::Kill() -{ - wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, - _T("a thread can't kill itself") ); - - switch ( m_internal->GetState() ) - { - case STATE_NEW: - case STATE_EXITED: - return wxTHREAD_NOT_RUNNING; - - case STATE_PAUSED: - // resume the thread first - Resume(); - - // fall through - - default: - OSStatus err = MPTerminateTask( m_internal->GetId() , -1 ) ; - if ( err ) - { - wxLogError(_("Failed to terminate a thread.")); - - return wxTHREAD_MISC_ERROR; - } - - if ( m_isDetached ) - { - delete this ; - } - else - { - // this should be retrieved by Wait actually - m_internal->SetExitCode((void*)-1); - } - - return wxTHREAD_NO_ERROR; - } -} - -void wxThread::Exit(ExitCode status) -{ - wxASSERT_MSG( This() == this, - _T("wxThread::Exit() can only be called in the context of the same thread") ); - - // don't enter m_critsect before calling OnExit() because the user code - // might deadlock if, for example, it signals a condition in OnExit() (a - // common case) while the main thread calls any of functions entering - // m_critsect on us (almost all of them do) - OnExit(); - - MPTerminateTask( m_internal->GetId() , (long) status) ; - - if ( IsDetached() ) - { - delete this; - } - else // joinable - { - // update the status of the joinable thread - wxCriticalSectionLocker lock(m_critsect); - m_internal->SetState(STATE_EXITED); - } -} - -// also test whether we were paused -bool wxThread::TestDestroy() -{ - wxASSERT_MSG( This() == this, - _T("wxThread::TestDestroy() can only be called in the context of the same thread") ); - - m_critsect.Enter(); - - if ( m_internal->GetState() == STATE_PAUSED ) - { - m_internal->SetReallyPaused(TRUE); - - // leave the crit section or the other threads will stop too if they - // try to call any of (seemingly harmless) IsXXX() functions while we - // sleep - m_critsect.Leave(); - - m_internal->Pause(); - } - else - { - // thread wasn't requested to pause, nothing to do - m_critsect.Leave(); - } - - return m_internal->WasCancelled(); -} - -// ----------------------------------------------------------------------------- -// priority setting -// ----------------------------------------------------------------------------- - -void wxThread::SetPriority(unsigned int prio) -{ - wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) && - ((int)prio <= (int)WXTHREAD_MAX_PRIORITY), - wxT("invalid thread priority") ); - - wxCriticalSectionLocker lock(m_critsect); - - switch ( m_internal->GetState() ) - { - case STATE_RUNNING: - case STATE_PAUSED: - case STATE_NEW: - // thread not yet started, priority will be set when it is - m_internal->SetPriority(prio); - break; - - case STATE_EXITED: - default: - wxFAIL_MSG(wxT("impossible to set thread priority in this state")); - } -} - -unsigned int wxThread::GetPriority() const -{ - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast - - return m_internal->GetPriority(); -} - -unsigned long wxThread::GetId() const -{ - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast - - return (unsigned long)m_internal->GetId(); -} - -// ----------------------------------------------------------------------------- -// state tests -// ----------------------------------------------------------------------------- - -bool wxThread::IsRunning() const -{ - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - - return m_internal->GetState() == STATE_RUNNING; -} - -bool wxThread::IsAlive() const -{ - wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect); - - switch ( m_internal->GetState() ) - { - case STATE_RUNNING: - case STATE_PAUSED: - return true; - - default: - return false; - } -} - -bool wxThread::IsPaused() const -{ - wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect); - - return (m_internal->GetState() == STATE_PAUSED); -} - -// ---------------------------------------------------------------------------- -// Automatic initialization for thread module -// ---------------------------------------------------------------------------- - -class wxThreadModule : public wxModule -{ -public: - virtual bool OnInit(); - virtual void OnExit(); - -private: - DECLARE_DYNAMIC_CLASS(wxThreadModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) - -bool wxThreadModule::OnInit() -{ - if ( !wxMacMPThreadsInitVerify() ) - { - return false ; - } - - verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread ) ) ; - // main thread's This() is NULL - verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread , NULL ) ) ; - - gs_idMainThread = wxThread::GetCurrentId() ; - - gs_critsectWaitingForGui = new wxCriticalSection(); - - gs_critsectGui = new wxCriticalSection(); - gs_critsectGui->Enter(); - - return true; -} - -void wxThreadModule::OnExit() -{ - if ( gs_critsectGui ) - { - gs_critsectGui->Leave(); - delete gs_critsectGui; - gs_critsectGui = NULL; - } - - delete gs_critsectWaitingForGui; - gs_critsectWaitingForGui = NULL; -} - -// ---------------------------------------------------------------------------- -// GUI Serialization copied from MSW implementation -// ---------------------------------------------------------------------------- - -void WXDLLIMPEXP_BASE wxMutexGuiEnter() -{ - // this would dead lock everything... - wxASSERT_MSG( !wxThread::IsMain(), - wxT("main thread doesn't want to block in wxMutexGuiEnter()!") ); - - // the order in which we enter the critical sections here is crucial!! - - // set the flag telling to the main thread that we want to do some GUI - { - wxCriticalSectionLocker enter(*gs_critsectWaitingForGui); - - gs_nWaitingForGui++; - } - - wxWakeUpMainThread(); - - // now we may block here because the main thread will soon let us in - // (during the next iteration of OnIdle()) - gs_critsectGui->Enter(); -} - -void WXDLLIMPEXP_BASE wxMutexGuiLeave() -{ - wxCriticalSectionLocker enter(*gs_critsectWaitingForGui); - - if ( wxThread::IsMain() ) - { - gs_bGuiOwnedByMainThread = false; - } - else - { - // decrement the number of threads waiting for GUI access now - wxASSERT_MSG( gs_nWaitingForGui > 0, - wxT("calling wxMutexGuiLeave() without entering it first?") ); - - gs_nWaitingForGui--; - - wxWakeUpMainThread(); - } - - gs_critsectGui->Leave(); -} - -void WXDLLIMPEXP_BASE wxMutexGuiLeaveOrEnter() -{ - wxASSERT_MSG( wxThread::IsMain(), - wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") ); - - wxCriticalSectionLocker enter(*gs_critsectWaitingForGui); - - if ( gs_nWaitingForGui == 0 ) - { - // no threads are waiting for GUI - so we may acquire the lock without - // any danger (but only if we don't already have it) - if ( !wxGuiOwnedByMainThread() ) - { - gs_critsectGui->Enter(); - - gs_bGuiOwnedByMainThread = true; - } - //else: already have it, nothing to do - } - else - { - // some threads are waiting, release the GUI lock if we have it - if ( wxGuiOwnedByMainThread() ) - { - wxMutexGuiLeave(); - } - //else: some other worker thread is doing GUI - } -} - -bool WXDLLIMPEXP_BASE wxGuiOwnedByMainThread() -{ - return gs_bGuiOwnedByMainThread; -} - -// wake up the main thread -void WXDLLEXPORT wxWakeUpMainThread() -{ - wxMacWakeUp() ; -} - -// ---------------------------------------------------------------------------- -// include common implementation code -// ---------------------------------------------------------------------------- - -#include "wx/thrimpl.cpp" - -#endif // wxUSE_THREADS