| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2012 The WebRTC Project Authors. All rights reserved. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license | |
| 5 * that can be found in the LICENSE file in the root of the source | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 #import "webrtc/base/maccocoasocketserver.h" | |
| 11 | |
| 12 #import <Foundation/Foundation.h> | |
| 13 #import <AppKit/AppKit.h> | |
| 14 | |
| 15 #include "webrtc/base/scoped_autorelease_pool.h" | |
| 16 | |
| 17 // MacCocoaSocketServerHelperRtc serves as a delegate to NSMachPort or a target
for | |
| 18 // a timeout. | |
| 19 @interface MacCocoaSocketServerHelperRtc : NSObject { | |
| 20 // This is a weak reference. This works fine since the | |
| 21 // rtc::MacCocoaSocketServer owns this object. | |
| 22 rtc::MacCocoaSocketServer* socketServer_; // Weak. | |
| 23 } | |
| 24 @end | |
| 25 | |
| 26 @implementation MacCocoaSocketServerHelperRtc | |
| 27 - (id)initWithSocketServer:(rtc::MacCocoaSocketServer*)ss { | |
| 28 self = [super init]; | |
| 29 if (self) { | |
| 30 socketServer_ = ss; | |
| 31 } | |
| 32 return self; | |
| 33 } | |
| 34 | |
| 35 - (void)timerFired:(NSTimer*)timer { | |
| 36 socketServer_->WakeUp(); | |
| 37 } | |
| 38 | |
| 39 - (void)breakMainloop { | |
| 40 [NSApp stop:self]; | |
| 41 // NSApp stop only exits after finishing processing of the | |
| 42 // current event. Since we're potentially in a timer callback | |
| 43 // and not an NSEvent handler, we need to trigger a dummy one | |
| 44 // and turn the loop over. We may be able to skip this if we're | |
| 45 // on the ss' thread and not inside the app loop already. | |
| 46 NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined | |
| 47 location:NSMakePoint(0,0) | |
| 48 modifierFlags:0 | |
| 49 timestamp:0 | |
| 50 windowNumber:0 | |
| 51 context:nil | |
| 52 subtype:0 | |
| 53 data1:0 | |
| 54 data2:0]; | |
| 55 [NSApp postEvent:event atStart:NO]; | |
| 56 } | |
| 57 @end | |
| 58 | |
| 59 namespace rtc { | |
| 60 | |
| 61 MacCocoaSocketServer::MacCocoaSocketServer() { | |
| 62 helper_ = [[MacCocoaSocketServerHelperRtc alloc] initWithSocketServer:this]; | |
| 63 timer_ = nil; | |
| 64 run_count_ = 0; | |
| 65 | |
| 66 // Initialize the shared NSApplication | |
| 67 [NSApplication sharedApplication]; | |
| 68 } | |
| 69 | |
| 70 MacCocoaSocketServer::~MacCocoaSocketServer() { | |
| 71 [timer_ invalidate]; | |
| 72 [timer_ release]; | |
| 73 [helper_ release]; | |
| 74 } | |
| 75 | |
| 76 // ::Wait is reentrant, for example when blocking on another thread while | |
| 77 // responding to I/O. Calls to [NSApp] MUST be made from the main thread | |
| 78 // only! | |
| 79 bool MacCocoaSocketServer::Wait(int cms, bool process_io) { | |
| 80 rtc::ScopedAutoreleasePool pool; | |
| 81 if (!process_io && cms == 0) { | |
| 82 // No op. | |
| 83 return true; | |
| 84 } | |
| 85 if ([NSApp isRunning]) { | |
| 86 // Only allow reentrant waiting if we're in a blocking send. | |
| 87 ASSERT(!process_io && cms == kForever); | |
| 88 } | |
| 89 | |
| 90 if (!process_io) { | |
| 91 // No way to listen to common modes and not get socket events, unless | |
| 92 // we disable each one's callbacks. | |
| 93 EnableSocketCallbacks(false); | |
| 94 } | |
| 95 | |
| 96 if (kForever != cms) { | |
| 97 // Install a timer that fires wakeup after cms has elapsed. | |
| 98 timer_ = | |
| 99 [NSTimer scheduledTimerWithTimeInterval:cms / 1000.0 | |
| 100 target:helper_ | |
| 101 selector:@selector(timerFired:) | |
| 102 userInfo:nil | |
| 103 repeats:NO]; | |
| 104 [timer_ retain]; | |
| 105 } | |
| 106 | |
| 107 // Run until WakeUp is called, which will call stop and exit this loop. | |
| 108 run_count_++; | |
| 109 [NSApp run]; | |
| 110 run_count_--; | |
| 111 | |
| 112 if (!process_io) { | |
| 113 // Reenable them. Hopefully this won't cause spurious callbacks or | |
| 114 // missing ones while they were disabled. | |
| 115 EnableSocketCallbacks(true); | |
| 116 } | |
| 117 | |
| 118 return true; | |
| 119 } | |
| 120 | |
| 121 // Can be called from any thread. Post a message back to the main thread to | |
| 122 // break out of the NSApp loop. | |
| 123 void MacCocoaSocketServer::WakeUp() { | |
| 124 if (timer_ != nil) { | |
| 125 [timer_ invalidate]; | |
| 126 [timer_ release]; | |
| 127 timer_ = nil; | |
| 128 } | |
| 129 | |
| 130 // [NSApp isRunning] returns unexpected results when called from another | |
| 131 // thread. Maintain our own count of how many times to break the main loop. | |
| 132 if (run_count_ > 0) { | |
| 133 [helper_ performSelectorOnMainThread:@selector(breakMainloop) | |
| 134 withObject:nil | |
| 135 waitUntilDone:false]; | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 } // namespace rtc | |
| OLD | NEW |