Bumping manifests a=b2g-bump
[gecko.git] / hal / gonk / UeventPoller.cpp
blobd394a1dfa9ce266326bbb6d61f75e0886e6f8de7
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <pthread.h>
20 #include <signal.h>
21 #include <string.h>
22 #include <strings.h>
23 #include <unistd.h>
25 #include <arpa/inet.h>
26 #include <linux/types.h>
27 #include <linux/netlink.h>
28 #include <netinet/in.h>
29 #include <sys/socket.h>
31 #include "nsDebug.h"
32 #include "base/message_loop.h"
33 #include "mozilla/FileUtils.h"
34 #include "nsAutoPtr.h"
35 #include "nsThreadUtils.h"
36 #include "nsXULAppAPI.h"
38 #include "UeventPoller.h"
40 namespace mozilla {
41 namespace hal_impl {
43 static void ShutdownUevent();
45 class NetlinkPoller : public MessageLoopForIO::Watcher
47 public:
48 NetlinkPoller() : mSocket(-1),
49 mIOLoop(MessageLoopForIO::current())
53 virtual ~NetlinkPoller() {}
55 bool OpenSocket();
57 virtual void OnFileCanReadWithoutBlocking(int fd);
59 // no writing to the netlink socket
60 virtual void OnFileCanWriteWithoutBlocking(int fd)
62 MOZ_CRASH("Must not write to netlink socket");
65 MessageLoopForIO *GetIOLoop () const { return mIOLoop; }
66 void RegisterObserver(IUeventObserver *aObserver)
68 mUeventObserverList.AddObserver(aObserver);
71 void UnregisterObserver(IUeventObserver *aObserver)
73 mUeventObserverList.RemoveObserver(aObserver);
74 if (mUeventObserverList.Length() == 0)
75 ShutdownUevent(); // this will destroy self
78 private:
79 ScopedClose mSocket;
80 MessageLoopForIO* mIOLoop;
81 MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
83 const static int kBuffsize = 64 * 1024;
84 uint8_t mBuffer [kBuffsize];
86 typedef ObserverList<NetlinkEvent> UeventObserverList;
87 UeventObserverList mUeventObserverList;
90 bool
91 NetlinkPoller::OpenSocket()
93 mSocket.rwget() = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
94 if (mSocket.get() < 0)
95 return false;
97 int sz = kBuffsize;
99 if (setsockopt(mSocket.get(), SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0)
100 return false;
102 // add FD_CLOEXEC flag
103 int flags = fcntl(mSocket.get(), F_GETFD);
104 if (flags == -1) {
105 return false;
107 flags |= FD_CLOEXEC;
108 if (fcntl(mSocket.get(), F_SETFD, flags) == -1)
109 return false;
111 // set non-blocking
112 if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1)
113 return false;
115 struct sockaddr_nl saddr;
116 bzero(&saddr, sizeof(saddr));
117 saddr.nl_family = AF_NETLINK;
118 saddr.nl_groups = 1;
119 saddr.nl_pid = gettid();
121 do {
122 if (bind(mSocket.get(), (struct sockaddr *)&saddr, sizeof(saddr)) == 0) {
123 break;
126 if (errno != EADDRINUSE) {
127 return false;
130 if (saddr.nl_pid == 0) {
131 return false;
134 // Once there was any other place in the same process assigning saddr.nl_pid by
135 // gettid(), we can detect it and print warning message.
136 printf_stderr("The netlink socket address saddr.nl_pid=%u is in use. Let the kernel re-assign.\n", saddr.nl_pid);
137 saddr.nl_pid = 0;
138 } while (true);
140 if (!mIOLoop->WatchFileDescriptor(mSocket.get(),
141 true,
142 MessageLoopForIO::WATCH_READ,
143 &mReadWatcher,
144 this)) {
145 return false;
148 return true;
151 static nsAutoPtr<NetlinkPoller> sPoller;
153 class UeventInitTask : public Task
155 virtual void Run()
157 if (!sPoller) {
158 return;
160 if (sPoller->OpenSocket()) {
161 return;
163 sPoller->GetIOLoop()->PostDelayedTask(FROM_HERE, new UeventInitTask(), 1000);
167 void
168 NetlinkPoller::OnFileCanReadWithoutBlocking(int fd)
170 MOZ_ASSERT(fd == mSocket.get());
171 while (true) {
172 int ret = read(fd, mBuffer, kBuffsize);
173 if (ret == -1) {
174 if (errno == EAGAIN || errno == EWOULDBLOCK) {
175 return;
177 if (errno == EINTR) {
178 continue;
181 if (ret <= 0) {
182 // fatal error on netlink socket which should not happen
183 _exit(1);
185 NetlinkEvent netlinkEvent;
186 netlinkEvent.decode(reinterpret_cast<char*>(mBuffer), ret);
187 mUeventObserverList.Broadcast(netlinkEvent);
191 static void
192 InitializeUevent()
194 MOZ_ASSERT(!sPoller);
195 sPoller = new NetlinkPoller();
196 sPoller->GetIOLoop()->PostTask(FROM_HERE, new UeventInitTask());
200 static void
201 ShutdownUevent()
203 sPoller = nullptr;
206 void
207 RegisterUeventListener(IUeventObserver *aObserver)
209 MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
211 if (!sPoller)
212 InitializeUevent();
213 sPoller->RegisterObserver(aObserver);
216 void
217 UnregisterUeventListener(IUeventObserver *aObserver)
219 MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
221 sPoller->UnregisterObserver(aObserver);
224 } // hal_impl
225 } // mozilla