1// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_
6#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_
7
8#include "base/base_export.h"
9#include "base/mac/scoped_cffiledescriptorref.h"
10#include "base/mac/scoped_cftyperef.h"
11#include "base/memory/ref_counted.h"
12#include "base/memory/weak_ptr.h"
13#include "base/message_loop/message_pump_mac.h"
14#include "base/observer_list.h"
15#include "base/threading/thread_checker.h"
16
17namespace base {
18
19// This file introduces a class to monitor sockets and issue callbacks when
20// sockets are ready for I/O on iOS.
21class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop {
22 public:
23  class IOObserver {
24   public:
25    IOObserver() {}
26
27    // An IOObserver is an object that receives IO notifications from the
28    // MessagePump.
29    //
30    // NOTE: An IOObserver implementation should be extremely fast!
31    virtual void WillProcessIOEvent() = 0;
32    virtual void DidProcessIOEvent() = 0;
33
34   protected:
35    virtual ~IOObserver() {}
36  };
37
38  // Used with WatchFileDescriptor to asynchronously monitor the I/O readiness
39  // of a file descriptor.
40  class Watcher {
41   public:
42    // Called from MessageLoop::Run when an FD can be read from/written to
43    // without blocking
44    virtual void OnFileCanReadWithoutBlocking(int fd) = 0;
45    virtual void OnFileCanWriteWithoutBlocking(int fd) = 0;
46
47   protected:
48    virtual ~Watcher() {}
49  };
50
51  // Object returned by WatchFileDescriptor to manage further watching.
52  class FileDescriptorWatcher {
53   public:
54    FileDescriptorWatcher();
55    ~FileDescriptorWatcher();  // Implicitly calls StopWatchingFileDescriptor.
56
57    // NOTE: These methods aren't called StartWatching()/StopWatching() to
58    // avoid confusion with the win32 ObjectWatcher class.
59
60    // Stop watching the FD, always safe to call.  No-op if there's nothing
61    // to do.
62    bool StopWatchingFileDescriptor();
63
64   private:
65    friend class MessagePumpIOSForIO;
66    friend class MessagePumpIOSForIOTest;
67
68    // Called by MessagePumpIOSForIO, ownership of |fdref| and |fd_source|
69    // is transferred to this object.
70    void Init(CFFileDescriptorRef fdref,
71              CFOptionFlags callback_types,
72              CFRunLoopSourceRef fd_source,
73              bool is_persistent);
74
75    void set_pump(base::WeakPtr<MessagePumpIOSForIO> pump) { pump_ = pump; }
76    const base::WeakPtr<MessagePumpIOSForIO>& pump() const { return pump_; }
77
78    void set_watcher(Watcher* watcher) { watcher_ = watcher; }
79
80    void OnFileCanReadWithoutBlocking(int fd, MessagePumpIOSForIO* pump);
81    void OnFileCanWriteWithoutBlocking(int fd, MessagePumpIOSForIO* pump);
82
83    bool is_persistent_;  // false if this event is one-shot.
84    base::mac::ScopedCFFileDescriptorRef fdref_;
85    CFOptionFlags callback_types_;
86    base::ScopedCFTypeRef<CFRunLoopSourceRef> fd_source_;
87    base::WeakPtr<MessagePumpIOSForIO> pump_;
88    Watcher* watcher_;
89
90    DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
91  };
92
93  enum Mode {
94    WATCH_READ = 1 << 0,
95    WATCH_WRITE = 1 << 1,
96    WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE
97  };
98
99  MessagePumpIOSForIO();
100  virtual ~MessagePumpIOSForIO();
101
102  // Have the current thread's message loop watch for a a situation in which
103  // reading/writing to the FD can be performed without blocking.
104  // Callers must provide a preallocated FileDescriptorWatcher object which
105  // can later be used to manage the lifetime of this event.
106  // If a FileDescriptorWatcher is passed in which is already attached to
107  // an event, then the effect is cumulative i.e. after the call |controller|
108  // will watch both the previous event and the new one.
109  // If an error occurs while calling this method in a cumulative fashion, the
110  // event previously attached to |controller| is aborted.
111  // Returns true on success.
112  // Must be called on the same thread the message_pump is running on.
113  bool WatchFileDescriptor(int fd,
114                           bool persistent,
115                           int mode,
116                           FileDescriptorWatcher *controller,
117                           Watcher *delegate);
118
119  void RemoveRunLoopSource(CFRunLoopSourceRef source);
120
121  void AddIOObserver(IOObserver* obs);
122  void RemoveIOObserver(IOObserver* obs);
123
124 private:
125  friend class MessagePumpIOSForIOTest;
126
127  void WillProcessIOEvent();
128  void DidProcessIOEvent();
129
130  static void HandleFdIOEvent(CFFileDescriptorRef fdref,
131                              CFOptionFlags callback_types,
132                              void* context);
133
134  ObserverList<IOObserver> io_observers_;
135  ThreadChecker watch_file_descriptor_caller_checker_;
136
137  base::WeakPtrFactory<MessagePumpIOSForIO> weak_factory_;
138
139  DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIO);
140};
141
142}  // namespace base
143
144#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_
145