X-Git-Url: https://git.saurik.com/apple/cf.git/blobdiff_plain/d8b101a4f6aa03fafcaee9105fbfdea9132c942c..d73847987a99375010c6d6ace0abb0a25cb9b034:/CFSocket.c diff --git a/CFSocket.c b/CFSocket.c index 44cd67c..cf64cca 100644 --- a/CFSocket.c +++ b/CFSocket.c @@ -2,14 +2,14 @@ * Copyright (c) 2014 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -17,12 +17,12 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ /* CFSocket.c - Copyright (c) 1999-2013, Apple Inc. All rights reserved. + Copyright (c) 1999-2014, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -210,8 +210,9 @@ static const CFRuntimeClass __CFSocketClass = { static CFMutableArrayRef __CFAllSockets = NULL; CFTypeID CFSocketGetTypeID(void) { - if (_kCFRuntimeNotATypeID == __kCFSocketTypeID) { - __kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass); + static dispatch_once_t initOnce; + dispatch_once(&initOnce, ^{ + __kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass); // initOnce covered __CFAllSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); struct rlimit lim1; int ret1 = getrlimit(RLIMIT_NOFILE, &lim1); @@ -227,7 +228,7 @@ CFTypeID CFSocketGetTypeID(void) { setrlimit(RLIMIT_NOFILE, &lim2); // we try, but do not go to extraordinary measures } - } + }); return __kCFSocketTypeID; } @@ -1055,9 +1056,9 @@ CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fd (2) an individual CFSocket's lock (3) __CFActiveSocketsLock */ -static CFSpinLock_t __CFAllSocketsLock = CFSpinLockInit; /* controls __CFAllSockets */ +static CFLock_t __CFAllSocketsLock = CFLockInit; /* controls __CFAllSockets */ static CFMutableDictionaryRef __CFAllSockets = NULL; -static CFSpinLock_t __CFActiveSocketsLock = CFSpinLockInit; /* controls __CFRead/WriteSockets, __CFRead/WriteSocketsFds, __CFSocketManagerThread, and __CFSocketManagerIteration */ +static CFLock_t __CFActiveSocketsLock = CFLockInit; /* controls __CFRead/WriteSockets, __CFRead/WriteSocketsFds, __CFSocketManagerThread, and __CFSocketManagerIteration */ static volatile UInt32 __CFSocketManagerIteration = 0; static CFMutableArrayRef __CFWriteSockets = NULL; static CFMutableArrayRef __CFReadSockets = NULL; @@ -1081,8 +1082,8 @@ struct __CFSocket { unsigned closeSignaled:1; // Have we seen FD_CLOSE? (only used on Win32) unsigned unused:13; } _f; - CFSpinLock_t _lock; - CFSpinLock_t _writeLock; + CFLock_t _lock; + CFLock_t _writeLock; CFSocketNativeHandle _socket; /* immutable */ SInt32 _socketType; SInt32 _errorCode; @@ -1105,6 +1106,13 @@ struct __CFSocket { int _bufferedReadError; CFMutableDataRef _leftoverBytes; + + // + // If the timeout is set on the CFSocketRef but we never get select() timeout + // because we always have some network events so select never times out (e.g. while having a large download). + // We need to notify any waiting buffered read clients if there is data available without relying on select timing out. + struct timeval _readBufferTimeoutNotificationTime; + Boolean _hitTheTimeout; }; /* Bit 6 in the base reserved bits is used for write-signalled state (mutable) */ @@ -1162,11 +1170,11 @@ CF_INLINE void __CFSocketSetCallBackTypes(CFSocketRef s, uint8_t types) { } CF_INLINE void __CFSocketLock(CFSocketRef s) { - __CFSpinLock(&(s->_lock)); + __CFLock(&(s->_lock)); } CF_INLINE void __CFSocketUnlock(CFSocketRef s) { - __CFSpinUnlock(&(s->_lock)); + __CFUnlock(&(s->_lock)); } CF_INLINE Boolean __CFSocketIsConnectionOriented(CFSocketRef s) { @@ -1325,9 +1333,9 @@ static void __CFSocketInitializeWinSock_Guts(void) { } CF_EXPORT void __CFSocketInitializeWinSock(void) { - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); __CFSocketInitializeWinSock_Guts(); - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); } CF_PRIVATE void __CFSocketCleanup(void) { @@ -1470,6 +1478,62 @@ static void __CFSocketHandleWrite(CFSocketRef s, Boolean callBackNow) { } } + +#if defined(LOG_CFSOCKET) + +static CFStringRef someAddrToString(CFAllocatorRef alloc, int (*fun) (int, struct sockaddr*, socklen_t*), const char* name, CFSocketNativeHandle s) +{ + CFStringRef resultString = NULL; + union { + struct sockaddr sa; + struct sockaddr_in sa4b; + struct sockaddr_in6 sa6b; + UInt8 static_buffer[SOCK_MAXADDRLEN]; + } u; + socklen_t addrlen = sizeof(u.static_buffer); + + uint16_t* pPort = NULL; + char buffer[1024]; + + if ((*fun) (s, &u.sa, &addrlen) != 0) + snprintf(buffer, sizeof(buffer), "error %d resolving %s address for socket %d", errno, name, s); + else { + void* pAddr = NULL; + + switch (u.sa.sa_family) { + case AF_INET: + pAddr = &u.sa4b.sin_addr; + pPort = &u.sa4b.sin_port; + break; + case AF_INET6: + pAddr = &u.sa6b.sin6_addr; + pPort = &u.sa6b.sin6_port; + break; + } + + if (pAddr == NULL || inet_ntop(u.sa.sa_family, pAddr, buffer, sizeof(buffer)) == NULL) + snprintf(buffer, sizeof(buffer), "[error %d converting %s address for socket %d]", pAddr != NULL? errno : EBADF, name, s); + } + if (pPort) { + resultString = CFStringCreateWithFormat(alloc, NULL, CFSTR("%s:%d"), buffer, htons(*pPort)); + } else { + resultString = CFStringCreateWithFormat(alloc, NULL, CFSTR("%s"), buffer); + } + return resultString; +} + +CFStringRef copyPeerAddress(CFAllocatorRef alloc, CFSocketNativeHandle s) +{ + return someAddrToString(alloc, getpeername, "peer", s); +} + +CFStringRef copyLocalAddress(CFAllocatorRef alloc, CFSocketNativeHandle s) +{ + return someAddrToString(alloc, getsockname, "local", s); +} + +#endif + static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout) { CFDataRef data = NULL, address = NULL; @@ -1529,10 +1593,10 @@ static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout) && (s->_f.client & kCFSocketDataCallBack) != 0 && (s->_f.disabled & kCFSocketDataCallBack) == 0 && __CFSocketIsScheduled(s) ) { - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); /* restore socket to fds */ __CFSocketSetFDForRead(s); - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); } } else if (__CFSocketReadCallBackType(s) == kCFSocketAcceptCallBack) { uint8_t name[MAX_SOCKADDR_LEN]; @@ -1567,10 +1631,10 @@ static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout) if ((s->_f.client & kCFSocketAcceptCallBack) != 0 && (s->_f.disabled & kCFSocketAcceptCallBack) == 0 && __CFSocketIsScheduled(s) ) { - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); /* restore socket to fds */ __CFSocketSetFDForRead(s); - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); } } else { __CFSocketLock(s); @@ -1589,11 +1653,13 @@ static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout) fprintf(stdout, "TIMEOUT - but no bytes, restoring to active set\n"); fflush(stdout); #endif + // Clear the timeout notification time if there is no prefetched data left + timerclear(&s->_readBufferTimeoutNotificationTime); - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); /* restore socket to fds */ __CFSocketSetFDForRead(s); - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); __CFSocketUnlock(s); return; } @@ -1605,10 +1671,42 @@ static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout) /* if our buffer has room, we go ahead and buffer */ if (ctRemaining > 0) { base = CFDataGetMutableBytePtr(s->_readBuffer); - - do { - ctRead = read(CFSocketGetNative(s), &base[s->_bytesToBufferPos], ctRemaining); - } while (ctRead == -1 && errno == EAGAIN); + + struct timeval timeBeforeRead = { 0 }; + gettimeofday(&timeBeforeRead, NULL); + + struct timeval deadlineTime = { 0 }; + timeradd(&timeBeforeRead, &s->_readBufferTimeout, &deadlineTime); + + struct timeval timeAfterRead = { 0 }; + + while (1) { + ctRead = read(CFSocketGetNative(s), &base[s->_bytesToBufferPos], ctRemaining); + + if (ctRead >= 0) { + break; + } + + if (errno != EAGAIN) { + break; + } + + gettimeofday(&timeAfterRead, NULL); + + if (timercmp(&timeAfterRead, &deadlineTime, >)) { +#if defined(LOG_CFSOCKET) + CFSocketNativeHandle fd = CFSocketGetNative(s); + CFStringRef peerName = copyPeerAddress(kCFAllocatorDefault, fd); + CFStringRef localName = copyLocalAddress(kCFAllocatorDefault, fd); + CFLog(kCFLogLevelCritical, CFSTR("ERROR: Buffered read of %llu bytes failed for fd %d (socket valid? %d fd valid? %d %@ => %@)"), ctRemaining, fd, __CFSocketIsValid(s), __CFNativeSocketIsValid(fd), localName, peerName); + if (peerName) + CFRelease(peerName); + if (localName) + CFRelease(localName); +#endif + break; + } + } switch (ctRead) { case -1: @@ -1629,16 +1727,23 @@ static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout) default: s->_bytesToBufferPos += ctRead; if (s->_bytesToBuffer != s->_bytesToBufferPos) { + + // Update the timeout notification time + struct timeval timeNow = { 0 }; + gettimeofday(&timeNow, NULL); + timeradd(&timeNow, &s->_readBufferTimeout, &s->_readBufferTimeoutNotificationTime); #if defined(LOG_CFSOCKET) fprintf(stdout, "READ %ld - need %ld MORE - GOING BACK FOR MORE\n", ctRead, s->_bytesToBuffer - s->_bytesToBufferPos); #endif - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); /* restore socket to fds */ __CFSocketSetFDForRead(s); - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); __CFSocketUnlock(s); return; } else { + // Clear the timeout notification time if the buffer is full + timerclear(&s->_readBufferTimeoutNotificationTime); #if defined(LOG_CFSOCKET) fprintf(stdout, "DONE READING (read %ld bytes) - GOING TO SIGNAL\n", ctRead); #endif @@ -1713,7 +1818,7 @@ void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s, CFTimeInterval timeout, C /* lock ordering is socket lock, activesocketslock */ /* activesocketslock protects our timeout calculation */ __CFSocketLock(s); - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); if (s->_bytesToBuffer != length) { CFIndex ctBuffer = s->_bytesToBufferPos - s->_bytesToBufferReadPos; @@ -1776,7 +1881,7 @@ void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s, CFTimeInterval timeout, C __CFReadSocketsTimeoutInvalid = true; } - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); __CFSocketUnlock(s); } @@ -1938,7 +2043,7 @@ manageSelectError() if (EBADF == selectError) { CFMutableArrayRef invalidSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); CFIndex cnt = CFArrayGetCount(__CFWriteSockets); CFIndex idx; for (idx = 0; idx < cnt; idx++) { @@ -1979,7 +2084,7 @@ manageSelectError() clearInvalidFileDescriptors(__CFWriteSocketsFds); } - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); for (idx = 0; idx < cnt; idx++) { CFSocketInvalidate(((CFSocketRef)CFArrayGetValueAtIndex(invalidSockets, idx))); @@ -1988,10 +2093,7 @@ manageSelectError() } } -#ifdef __GNUC__ -__attribute__ ((noreturn)) // mostly interesting for shutting up a warning -#endif /* __GNUC__ */ -static void __CFSocketManager(void * arg) +static void *__CFSocketManager(void * arg) { pthread_setname_np("com.apple.CFSocket.private"); if (objc_collectingEnabled()) objc_registerThreadWithCollector(); @@ -2011,8 +2113,8 @@ static void __CFSocketManager(void * arg) struct timeval* pTimeout = NULL; struct timeval timeBeforeSelect; - for (;;) { - __CFSpinLock(&__CFActiveSocketsLock); + for (;;) { + __CFLock(&__CFActiveSocketsLock); __CFSocketManagerIteration++; #if defined(LOG_CFSOCKET) fprintf(stdout, "socket manager iteration %lu looking at read sockets ", (unsigned long)__CFSocketManagerIteration); @@ -2065,7 +2167,7 @@ static void __CFSocketManager(void * arg) gettimeofday(&timeBeforeSelect, NULL); } - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); #if DEPLOYMENT_TARGET_WINDOWS // On Windows, select checks connection failed sockets via the exceptfds parameter. connection succeeded is checked via writefds. We need both. @@ -2091,7 +2193,7 @@ static void __CFSocketManager(void * arg) fprintf(stdout, "Socket manager received timeout - kicking off expired reads (expired delta %ld, %d)\n", deltaTime.tv_sec, deltaTime.tv_usec); #endif - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); tempfds = NULL; cnt = CFArrayGetCount(__CFReadSockets); @@ -2117,7 +2219,7 @@ static void __CFSocketManager(void * arg) } } - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); /* and below, we dispatch through the normal read dispatch mechanism */ } @@ -2132,7 +2234,7 @@ static void __CFSocketManager(void * arg) fprintf(stdout, "socket manager received %c on wakeup socket\n", buffer[0]); #endif } - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); tempfds = NULL; cnt = CFArrayGetCount(__CFWriteSockets); for (idx = 0; idx < cnt; idx++) { @@ -2155,6 +2257,12 @@ static void __CFSocketManager(void * arg) } tempfds = NULL; cnt = CFArrayGetCount(__CFReadSockets); + + struct timeval timeNow = { 0 }; + if (pTimeout) { + gettimeofday(&timeNow, NULL); + } + for (idx = 0; idx < cnt; idx++) { CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFReadSockets, idx); CFSocketNativeHandle sock = s->_socket; @@ -2162,7 +2270,17 @@ static void __CFSocketManager(void * arg) // in which case we must be sure not to test a bit in the fdset that is // outside our mask size. Boolean sockInBounds = (0 <= sock && sock < maxnrfds); - if (INVALID_SOCKET != sock && sockInBounds && FD_ISSET(sock, readfds)) { + + // Check if we hit the timeout + s->_hitTheTimeout = false; + if (pTimeout && sockInBounds && 0 != nrfds && !FD_ISSET(sock, readfds) && + timerisset(&s->_readBufferTimeoutNotificationTime) && + timercmp(&timeNow, &s->_readBufferTimeoutNotificationTime, >)) + { + s->_hitTheTimeout = true; + } + + if (INVALID_SOCKET != sock && sockInBounds && (FD_ISSET(sock, readfds) || s->_hitTheTimeout)) { CFArraySetValueAtIndex(selectedReadSockets, selectedReadSocketsIndex, s); selectedReadSocketsIndex++; /* socket is removed from fds here, will be restored in read handling or in perform function */ @@ -2170,7 +2288,7 @@ static void __CFSocketManager(void * arg) FD_CLR(sock, tempfds); } } - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); for (idx = 0; idx < selectedWriteSocketsIndex; idx++) { CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(selectedWriteSockets, idx); @@ -2189,11 +2307,12 @@ static void __CFSocketManager(void * arg) #if defined(LOG_CFSOCKET) fprintf(stdout, "socket manager signaling socket %d for read\n", s->_socket); #endif - __CFSocketHandleRead(s, nrfds == 0); + __CFSocketHandleRead(s, nrfds == 0 || s->_hitTheTimeout); CFArraySetValueAtIndex(selectedReadSockets, idx, kCFNull); } selectedReadSocketsIndex = 0; } + return NULL; } static CFStringRef __CFSocketCopyDescription(CFTypeRef cf) { @@ -2266,8 +2385,9 @@ static const CFRuntimeClass __CFSocketClass = { }; CFTypeID CFSocketGetTypeID(void) { - if (_kCFRuntimeNotATypeID == __kCFSocketTypeID) { - __kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass); + static dispatch_once_t initOnce; + dispatch_once(&initOnce, ^{ + __kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass); // initOnce covered #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI struct rlimit lim1; int ret1 = getrlimit(RLIMIT_NOFILE, &lim1); @@ -2284,38 +2404,54 @@ CFTypeID CFSocketGetTypeID(void) { // we try, but do not go to extraordinary measures } #endif - } + }); return __kCFSocketTypeID; } +#if DEPLOYMENT_TARGET_WINDOWS +struct _args { + void *func; + void *arg; + HANDLE handle; +}; +static unsigned __stdcall __CFWinThreadFunc(void *arg) { + struct _args *args = (struct _args*)arg; + ((void (*)(void *))args->func)(args->arg); + CloseHandle(args->handle); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, arg); + _endthreadex(0); + return 0; +} +#endif + static CFSocketRef _CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle sock, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context, Boolean useExistingInstance) { CHECK_FOR_FORK(); CFSocketRef memory; int typeSize = sizeof(memory->_socketType); - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); if (NULL == __CFReadSockets) __CFSocketInitializeSockets(); - __CFSpinUnlock(&__CFActiveSocketsLock); - __CFSpinLock(&__CFAllSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); + __CFLock(&__CFAllSocketsLock); if (NULL == __CFAllSockets) { __CFAllSockets = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); } if (INVALID_SOCKET != sock && CFDictionaryGetValueIfPresent(__CFAllSockets, (void *)(uintptr_t)sock, (const void **)&memory)) { if (useExistingInstance) { - __CFSpinUnlock(&__CFAllSocketsLock); + __CFUnlock(&__CFAllSocketsLock); CFRetain(memory); return memory; } else { #if defined(LOG_CFSOCKET) fprintf(stdout, "useExistingInstance is FALSE, removing existing instance %p from __CFAllSockets\n", memory); #endif - __CFSpinUnlock(&__CFAllSocketsLock); + __CFUnlock(&__CFAllSocketsLock); CFSocketInvalidate(memory); - __CFSpinLock(&__CFAllSocketsLock); + __CFLock(&__CFAllSocketsLock); } } memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, CFSocketGetTypeID(), sizeof(struct __CFSocket) - sizeof(CFRuntimeBase), NULL); if (NULL == memory) { - __CFSpinUnlock(&__CFAllSocketsLock); + __CFUnlock(&__CFAllSocketsLock); return NULL; } __CFSocketSetCallBackTypes(memory, callBackTypes); @@ -2327,8 +2463,8 @@ static CFSocketRef _CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketN memory->_f.connected = FALSE; memory->_f.writableHint = FALSE; memory->_f.closeSignaled = FALSE; - memory->_lock = CFSpinLockInit; - memory->_writeLock = CFSpinLockInit; + memory->_lock = CFLockInit; + memory->_writeLock = CFLockInit; memory->_socket = sock; if (INVALID_SOCKET == sock || 0 != getsockopt(sock, SOL_SOCKET, SO_TYPE, (char *)&(memory->_socketType), (socklen_t *)&typeSize)) memory->_socketType = 0; // cast for WinSock bad API memory->_errorCode = 0; @@ -2349,6 +2485,8 @@ static CFSocketRef _CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketN memory->_context.release = 0; memory->_context.copyDescription = 0; timerclear(&memory->_readBufferTimeout); + timerclear(&memory->_readBufferTimeoutNotificationTime); + memory->_hitTheTimeout = false; memory->_readBuffer = NULL; memory->_bytesToBuffer = 0; memory->_bytesToBufferPos = 0; @@ -2358,8 +2496,33 @@ static CFSocketRef _CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketN memory->_leftoverBytes = NULL; if (INVALID_SOCKET != sock) CFDictionaryAddValue(__CFAllSockets, (void *)(uintptr_t)sock, memory); - if (NULL == __CFSocketManagerThread) __CFSocketManagerThread = __CFStartSimpleThread(__CFSocketManager, 0); - __CFSpinUnlock(&__CFAllSocketsLock); + if (NULL == __CFSocketManagerThread) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD + pthread_t tid = 0; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_attr_set_qos_class_np(&attr, qos_class_main(), 0); + pthread_create(&tid, &attr, __CFSocketManager, 0); + pthread_attr_destroy(&attr); +//warning CF: we dont actually know that a pthread_t is the same size as void * + __CFSocketManagerThread = (void *)tid; +#elif DEPLOYMENT_TARGET_WINDOWS + unsigned tid; + struct _args *args = (struct _args*)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct _args), 0); + if (__CFOASafe) __CFSetLastAllocationEventName(args, "CFUtilities (thread-args)"); + HANDLE handle; + args->func = __CFSocketManager; + args->arg = 0; + /* The thread is created suspended, because otherwise there would be a race between the assignment below of the handle field, and it's possible use in the thread func above. */ + args->handle = (HANDLE)_beginthreadex(NULL, 0, __CFWinThreadFunc, args, CREATE_SUSPENDED, &tid); + handle = args->handle; + ResumeThread(handle); + __CFSocketManagerThread = handle; +#endif + } + __CFUnlock(&__CFAllSocketsLock); if (NULL != context) { void *contextInfo = context->retain ? (void *)context->retain(context->info) : context->info; __CFSocketLock(memory); @@ -2388,7 +2551,7 @@ void CFSocketInvalidate(CFSocketRef s) { fprintf(stdout, "invalidating socket %d with flags 0x%x disabled 0x%x connected 0x%x\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected); #endif CFRetain(s); - __CFSpinLock(&__CFAllSocketsLock); + __CFLock(&__CFAllSocketsLock); __CFSocketLock(s); if (__CFSocketIsValid(s)) { SInt32 idx; @@ -2398,7 +2561,7 @@ void CFSocketInvalidate(CFSocketRef s) { __CFSocketUnsetValid(s); __CFSocketUnsetWriteSignalled(s); __CFSocketUnsetReadSignalled(s); - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); idx = CFArrayGetFirstIndexOfValue(__CFWriteSockets, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets)), s); if (0 <= idx) { CFArrayRemoveValueAtIndex(__CFWriteSockets, idx); @@ -2411,7 +2574,7 @@ void CFSocketInvalidate(CFSocketRef s) { __CFSocketClearFDForRead(s); } previousSocketManagerIteration = __CFSocketManagerIteration; - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); CFDictionaryRemoveValue(__CFAllSockets, (void *)(uintptr_t)(s->_socket)); if ((s->_f.client & kCFSocketCloseOnInvalidate) != 0) closesocket(s->_socket); s->_socket = INVALID_SOCKET; @@ -2460,7 +2623,7 @@ void CFSocketInvalidate(CFSocketRef s) { } else { __CFSocketUnlock(s); } - __CFSpinUnlock(&__CFAllSocketsLock); + __CFUnlock(&__CFAllSocketsLock); CFRelease(s); #if defined(LOG_CFSOCKET) CFLog(5, CFSTR("CFSocketInvalidate(%p) done"), s); @@ -2549,7 +2712,7 @@ void CFSocketDisableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) { #if defined(LOG_CFSOCKET) fprintf(stdout, "unscheduling socket %d with flags 0x%x disabled 0x%x connected 0x%x for types 0x%lx\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected, callBackTypes); #endif - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); if ((readCallBackType == kCFSocketAcceptCallBack) || !__CFSocketIsConnectionOriented(s)) s->_f.connected = TRUE; if (((callBackTypes & kCFSocketWriteCallBack) != 0) || (((callBackTypes & kCFSocketConnectCallBack) != 0) && !s->_f.connected)) { if (__CFSocketClearFDForWrite(s)) { @@ -2565,7 +2728,7 @@ void CFSocketDisableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) { if (readCallBackType != kCFSocketReadCallBack) wakeup = true; } } - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); } __CFSocketUnlock(s); } @@ -2607,7 +2770,7 @@ void __CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes, Boole // Now turn on the callbacks we've determined that we want on if (turnOnRead || turnOnWrite || turnOnConnect) { - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); if (turnOnWrite || turnOnConnect) { if (force) { SInt32 idx = CFArrayGetFirstIndexOfValue(__CFWriteSockets, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets)), s); @@ -2623,7 +2786,7 @@ void __CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes, Boole } if (__CFSocketSetFDForRead(s)) wakeup = true; } - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); } } __CFSocketUnlock(s); @@ -2669,7 +2832,7 @@ static void __CFSocketCancel(void *info, CFRunLoopRef rl, CFStringRef mode) { __CFSocketLock(s); s->_socketSetCount--; if (0 == s->_socketSetCount) { - __CFSpinLock(&__CFActiveSocketsLock); + __CFLock(&__CFActiveSocketsLock); idx = CFArrayGetFirstIndexOfValue(__CFWriteSockets, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets)), s); if (0 <= idx) { // CFLog(5, CFSTR("__CFSocketCancel: removing %p from __CFWriteSockets list"), s); @@ -2681,7 +2844,7 @@ static void __CFSocketCancel(void *info, CFRunLoopRef rl, CFStringRef mode) { CFArrayRemoveValueAtIndex(__CFReadSockets, idx); __CFSocketClearFDForRead(s); } - __CFSpinUnlock(&__CFActiveSocketsLock); + __CFUnlock(&__CFActiveSocketsLock); } if (NULL != s->_runLoops) { CFMutableArrayRef runLoopsOrig = s->_runLoops; @@ -2905,15 +3068,15 @@ CONST_STRING_DECL(kCFSocketRegisterCommand, "Register") CONST_STRING_DECL(kCFSocketRetrieveCommand, "Retrieve") CONST_STRING_DECL(__kCFSocketRegistryRequestRunLoopMode, "CFSocketRegistryRequest") -static CFSpinLock_t __CFSocketWriteLock_ = CFSpinLockInit; +static CFLock_t __CFSocketWriteLock_ = CFLockInit; //#warning can only send on one socket at a time now CF_INLINE void __CFSocketWriteLock(CFSocketRef s) { - __CFSpinLock(& __CFSocketWriteLock_); + __CFLock(& __CFSocketWriteLock_); } CF_INLINE void __CFSocketWriteUnlock(CFSocketRef s) { - __CFSpinUnlock(& __CFSocketWriteLock_); + __CFUnlock(& __CFSocketWriteLock_); } #if NEW_SOCKET @@ -3154,7 +3317,7 @@ static void __CFSocketHandleNameRegistryReply(CFSocketRef s, CFSocketCallBackTyp __CFSocketNameRegistryResponse *response = (__CFSocketNameRegistryResponse *)info; CFDictionaryRef replyDictionary = NULL; CFPropertyListRef value; - replyDictionary = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, replyData, kCFPropertyListImmutable, NULL); + replyDictionary = (CFDictionaryRef)CFPropertyListCreateWithData(kCFAllocatorSystemDefault, replyData, kCFPropertyListImmutable, NULL, NULL); if (NULL != response->error) *(response->error) = kCFSocketError; if (NULL != replyDictionary) { if (CFGetTypeID((CFTypeRef)replyDictionary) == CFDictionaryGetTypeID() && NULL != (value = CFDictionaryGetValue(replyDictionary, kCFSocketResultKey))) { @@ -3173,7 +3336,7 @@ static void __CFSocketSendNameRegistryRequest(CFSocketSignature *signature, CFDi CFSocketRef s = NULL; CFRunLoopSourceRef source = NULL; if (NULL != response->error) *(response->error) = kCFSocketError; - requestData = CFPropertyListCreateXMLData(kCFAllocatorSystemDefault, requestDictionary); + requestData = CFPropertyListCreateData(kCFAllocatorSystemDefault, requestDictionary, kCFPropertyListXMLFormat_v1_0, 0, NULL); if (NULL != requestData) { if (NULL != response->error) *(response->error) = kCFSocketTimeout; s = CFSocketCreateConnectedToSocketSignature(kCFAllocatorSystemDefault, signature, kCFSocketDataCallBack, __CFSocketHandleNameRegistryReply, &context, timeout);