1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "DBusWatcher.h"
8 #include "mozilla/Unused.h"
9 #include "nsThreadUtils.h"
10
11 namespace mozilla {
12 namespace ipc {
13
DBusWatcher(DBusConnection * aConnection,DBusWatch * aWatch)14 DBusWatcher::DBusWatcher(DBusConnection* aConnection, DBusWatch* aWatch)
15 : mConnection(aConnection)
16 , mWatch(aWatch)
17 {
18 MOZ_ASSERT(mConnection);
19 MOZ_ASSERT(mWatch);
20 }
21
~DBusWatcher()22 DBusWatcher::~DBusWatcher()
23 { }
24
25 DBusConnection*
GetConnection()26 DBusWatcher::GetConnection()
27 {
28 return mConnection;
29 }
30
31 void
StartWatching()32 DBusWatcher::StartWatching()
33 {
34 MOZ_ASSERT(!NS_IsMainThread());
35
36 auto flags = dbus_watch_get_flags(mWatch);
37
38 if (!(flags & (DBUS_WATCH_READABLE|DBUS_WATCH_WRITABLE))) {
39 return;
40 }
41
42 auto ioLoop = MessageLoopForIO::current();
43
44 auto fd = dbus_watch_get_unix_fd(mWatch);
45
46 if (flags & DBUS_WATCH_READABLE) {
47 ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_READ,
48 &mReadWatcher, this);
49 }
50 if (flags & DBUS_WATCH_WRITABLE) {
51 ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_WRITE,
52 &mWriteWatcher, this);
53 }
54 }
55
56 void
StopWatching()57 DBusWatcher::StopWatching()
58 {
59 MOZ_ASSERT(!NS_IsMainThread());
60
61 auto flags = dbus_watch_get_flags(mWatch);
62
63 if (flags & DBUS_WATCH_READABLE) {
64 mReadWatcher.StopWatchingFileDescriptor();
65 }
66 if (flags & DBUS_WATCH_WRITABLE) {
67 mWriteWatcher.StopWatchingFileDescriptor();
68 }
69 }
70
71 // DBus utility functions, used as function pointers in DBus setup
72
73 void
FreeFunction(void * aData)74 DBusWatcher::FreeFunction(void* aData)
75 {
76 UniquePtr<DBusWatcher> watcher(static_cast<DBusWatcher*>(aData));
77 }
78
79 dbus_bool_t
AddWatchFunction(DBusWatch * aWatch,void * aData)80 DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData)
81 {
82 MOZ_ASSERT(!NS_IsMainThread());
83
84 auto connection = static_cast<DBusConnection*>(aData);
85
86 UniquePtr<DBusWatcher> dbusWatcher =
87 MakeUnique<DBusWatcher>(connection, aWatch);
88
89 dbus_watch_set_data(aWatch, dbusWatcher.get(), DBusWatcher::FreeFunction);
90
91 if (dbus_watch_get_enabled(aWatch)) {
92 dbusWatcher->StartWatching();
93 }
94
95 Unused << dbusWatcher.release(); // picked up in |FreeFunction|
96
97 return TRUE;
98 }
99
100 void
RemoveWatchFunction(DBusWatch * aWatch,void * aData)101 DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData)
102 {
103 MOZ_ASSERT(!NS_IsMainThread());
104
105 auto dbusWatcher = static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
106
107 dbusWatcher->StopWatching();
108 }
109
110 void
ToggleWatchFunction(DBusWatch * aWatch,void * aData)111 DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData)
112 {
113 MOZ_ASSERT(!NS_IsMainThread());
114
115 auto dbusWatcher = static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
116
117 if (dbus_watch_get_enabled(aWatch)) {
118 dbusWatcher->StartWatching();
119 } else {
120 dbusWatcher->StopWatching();
121 }
122 }
123
124 // I/O-loop callbacks
125
126 void
OnFileCanReadWithoutBlocking(int aFd)127 DBusWatcher::OnFileCanReadWithoutBlocking(int aFd)
128 {
129 MOZ_ASSERT(!NS_IsMainThread());
130
131 dbus_watch_handle(mWatch, DBUS_WATCH_READABLE);
132
133 DBusDispatchStatus dbusDispatchStatus;
134
135 do {
136 dbusDispatchStatus = dbus_connection_dispatch(mConnection);
137 } while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
138 }
139
140 void
OnFileCanWriteWithoutBlocking(int aFd)141 DBusWatcher::OnFileCanWriteWithoutBlocking(int aFd)
142 {
143 MOZ_ASSERT(!NS_IsMainThread());
144
145 dbus_watch_handle(mWatch, DBUS_WATCH_WRITABLE);
146 }
147
148 } // namespace ipc
149 } // namespace mozilla
150