Ok, let's see if we can get a grip on what is going on. what I did was in sqSocketCreateNetTypeSocketTypeRecvBytesSendBytesSemaIDReadSemaIDWriteSemaID after the socket() call and at the check for socket value = -1, I always fail the primitive call. This mimics what happens when you run out of socket handles. In this case since we never recover then it should result in a hard failure because the socket table is full. I put a break point in to understand where we are, and a breakpoint at the full GC. What I see is the first call, where we fail. current pharo, closure based, macintosh vm 4.1.1b2 Process 557974616 Socket>initialize:family: 557974524 >newTCP: 557974308 BlockClosure>repeatWithGCIf: 557974216 >newTCP: 557974124 >newTCP 557973968 >new 557652968 >sendTest 557652876 >? 557649476 Compiler>evaluate:in:to:notifying:ifFail:logged: 557649384 ParagraphEditor>evaluateSelection 557649228 BlockClosure>on:do: 557649136 ParagraphEditor>evaluateSelection 557649024 ParagraphEditor>doIt The second call I note the full GC hasn't happened yet, so the code is invoking create new socket again before the GC call, which *IS* rather pointless. I wonder why the second call happens before the GC? Process 557976760 Socket
primSocketCreateNetwork:type:receiveBufferSize:sendBufSize:semaIndex:readSemaIndex:writeSemaIndex : 557974616 Socket>initialize:family: 557974524 >newTCP: 557974308 BlockClosure>repeatWithGCIf: 557974216 >newTCP: 557974124 >newTCP 557973968 >new 557652968 >sendTest 557652876 >? 557649476 Compiler>evaluate:in:to:notifying:ifFail:logged: 557649384 ParagraphEditor>evaluateSelection 557649228 BlockClosure>on:do: 557649136 ParagraphEditor>evaluateSelection 557649024 ParagraphEditor>doIt then we see the full GC which has the intent of cleaning out zombies so that those sockets can be returned to the operating system. Process 557683240 SystemDictionary>garbageCollect 557683044 BlockClosure>repeatWithGCIf: 557682952 >newTCP: 557682860 >newTCP 557682768 >new 557652968 >sendTest 557652876 >? 557649476 Compiler>evaluate:in:to:notifying:ifFail:logged: 557649384 ParagraphEditor>evaluateSelection 557649228 BlockClosure>on:do: 557649136 ParagraphEditor>evaluateSelection 557649024 ParagraphEditor>doIt then again Process 556761248 Socket>initialize:family: 556719648 >newTCP: 556692112 BlockClosure>repeatWithGCIf: 556692020 >newTCP: 556691928 >newTCP 556691836 >new 556662076 >sendTest 556661984 >? 556658584 Compiler>evaluate:in:to:notifying:ifFail:logged: 556658492 ParagraphEditor>evaluateSelection 556658336 BlockClosure>on:do: 556658244 ParagraphEditor>evaluateSelection 556658132 ParagraphEditor>doIt and again, which seems rather pointless. Process 556763348 Socket
primSocketCreateNetwork:type:receiveBufferSize:sendBufSize:semaIndex:readSemaIndex:writeSemaIndex : 556761248 Socket>initialize:family: 556719648 >newTCP: 556692112 BlockClosure>repeatWithGCIf: 556692020 >newTCP: 556691928 >newTCP 556691836 >new 556662076 >sendTest 556661984 >? 556658584 Compiler>evaluate:in:to:notifying:ifFail:logged: 5566584\92 ParagraphEditor>evaluateSelection 556658336 BlockClosure>on:do: 556658244 ParagraphEditor>evaluateSelection 556658132 ParagraphEditor>doIt Then the walkback pops up. Obviously should the code try to make the socket 4 times? versus say twice? Socket>>connectNonBlockingTo: Receiver: a Socket[destroyed] Arguments and temporary variables: aSocketAddress: 128.111.221.123(pulse),9(discard) status: -1 Receiver's instance variables: semaphore: nil socketHandle: nil readSemaphore: nil writeSemaphore: nil primitiveOnlySupportsOneSemaphore: true Socket>>connectTo:waitForConnectionFor: Receiver: a Socket[destroyed] Arguments and temporary variables: aSocketAddress: 128.111.221.123(pulse),9(discard) timeout: 45 Receiver's instance variables: semaphore: nil socketHandle: nil readSemaphore: nil writeSemaphore: nil primitiveOnlySupportsOneSemaphore: true Socket>>connectTo: Receiver: a Socket[destroyed] Arguments and temporary variables: aSocketAddress: 128.111.221.123(pulse),9(discard) Receiver's instance variables: semaphore: nil socketHandle: nil readSemaphore: nil writeSemaphore: nil primitiveOnlySupportsOneSemaphore: true Socket>>connectTo:port: Receiver: a Socket[destroyed] Arguments and temporary variables: hostAddress: 128.111.221.123(pulse),9(discard) port: 9 Receiver's instance variables: semaphore: nil socketHandle: nil readSemaphore: nil writeSemaphore: nil primitiveOnlySupportsOneSemaphore: true Socket class>>sendTest Receiver: Socket Arguments and temporary variables: sock: a Socket[destroyed] bytesToSend: nil sendBuf: nil t: nil serverName: 'create.ucsb.edu' serverAddr: 128.111.221.123(pulse),9(discard) bytesSent: #(nil) Receiver's instance variables: superclass: Object methodDict: a MethodDictionary(size 137) format: 140 instanceVariables: #('semaphore' 'socketHandle' 'readSemaphore' 'writeSemaphore...etc... organization: ('accessing' address localAddress localPort peerName port primiti...etc... subclasses: {SocksSocket . HTTPSocket . RFBSocket} name: #Socket classPool: a Dictionary(#Connected->2 #DeadServer-
'update.squeakfoundation.org...etc... sharedPools: nil environment: Smalltalk category: #'Network-Kernel' traitComposition: {} localSelectors: nil
Socket class>>DoIt Receiver: Socket Arguments and temporary variables: Receiver's instance variables: superclass: Object methodDict: a MethodDictionary(size 137) format: 140 instanceVariables: #('semaphore' 'socketHandle' 'readSemaphore' 'writeSemaphore...etc... organization: ('accessing' address localAddress localPort peerName port primiti...etc... subclasses: {SocksSocket . HTTPSocket . RFBSocket} name: #Socket classPool: a Dictionary(#Connected->2 #DeadServer-
'update.squeakfoundation.org...etc... sharedPools: nil environment: Smalltalk category: #'Network-Kernel' traitComposition: {} localSelectors: nil
For cross check let's look at what happens before the closure code. pre closure work in a pharo0.1-10211dev09.01.3.image (gdb) call (int) printAllStacks() Process 545073376 Socket>initialize: 545073560 [] in >newTCP 545073284 BlockContext>repeatWithGCIf: 545072904 >newTCP 545072812 >new 544992420 >sendTest 544992328 >? 544989336 Compiler>evaluate:in:to:notifying:ifFail:logged: 544989004 [] in ParagraphEditor>evaluateSelection 544988912 BlockContext>on:do: 544988664 ParagraphEditor>evaluateSelection 544988572 ParagraphEditor>doIt again 545075672 Socket
primSocketCreateNetwork:type:receiveBufferSize:sendBufSize:semaIndex:readSemaIndex:writeSemaIndex : 545073376 Socket>initialize: 545073560 [] in >newTCP 545073284 BlockContext>repeatWithGCIf: 545072904 >newTCP 545072812 >new 544992420 >sendTest 544992328 >? 544989336 Compiler>evaluate:in:to:notifying:ifFail:logged: 544989004 [] in ParagraphEditor>evaluateSelection 544988912 BlockContext>on:do: 544988664 ParagraphEditor>evaluateSelection 544988572 ParagraphEditor>doIt fullGC happens. Process 545024744 SystemDictionary>garbageCollect 545024440 BlockContext>repeatWithGCIf: 545024336 >newTCP 545024244 >new 544992420 >sendTest 544992328 >? 544989336 Compiler>evaluate:in:to:notifying:ifFail:logged: 544989004 [] in ParagraphEditor>evaluateSelection 544988912 BlockContext>on:do: 544988664 ParagraphEditor>evaluateSelection 544988572 ParagraphEditor>doIt off we go again to create socket. Process 543469672 Socket>initialize: 543447120 [] in >newTCP 543447028 BlockContext>repeatWithGCIf: 543446924 >newTCP 543446832 >new 543438208 >sendTest 543438116 >? 543435124 Compiler>evaluate:in:to:notifying:ifFail:logged: 543434792 [] in ParagraphEditor>evaluateSelection 543434700 BlockContext>on:do: 543434452 ParagraphEditor>evaluateSelection 543434360 ParagraphEditor>doIt off we go again to create socket. Process 543471784 Socket
primSocketCreateNetwork:type:receiveBufferSize:sendBufSize:semaIndex:readSemaIndex:writeSemaIndex : 543469672 Socket>initialize: 543447120 [] in >newTCP 543447028 BlockContext>repeatWithGCIf: 543446924 >newTCP 543446832 >new 543438208 >sendTest 543438116 >? 543435124 Compiler>evaluate:in:to:notifying:ifFail:logged: 543434792 [] in ParagraphEditor>evaluateSelection 543434700 BlockContext>on:do: 543434452 ParagraphEditor>evaluateSelection 543434360 ParagraphEditor>doIt and end up with walkback at. Socket status must Unconnected before opening a new connection connectNonBlockingTo: hostAddress port: port "Initiate a connection to the given port at the given host address. This operation will return immediately; follow it with waitForConnectionUntil: to wait until the connection is established." | status | self initializeNetwork. status := self primSocketConnectionStatus: socketHandle. (status == Unconnected) ifFalse: [InvalidSocketStatusException signal: 'Socket status must Unconnected before opening a new connection']. = = = ======================================================================== John M. McIntosh <johnmci@smalltalkconsulting.com> Twitter: squeaker68882 Corporate Smalltalk Consulting Ltd. http://www.smalltalkconsulting.com = = = ========================================================================