OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 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 #include "media/audio/shared_mem_synchronizer.h" | |
6 | |
7 #if defined(OS_POSIX) | |
8 #include <errno.h> | |
9 #include <sys/poll.h> | |
10 #endif | |
11 | |
12 #include "base/logging.h" | |
13 #include "base/memory/scoped_ptr.h" | |
14 | |
15 #if defined(OS_POSIX) | |
16 #include "base/file_descriptor_posix.h" | |
17 #endif | |
18 | |
19 SharedMemSynchronizer::WaitForMultiple::WaitForMultiple( | |
20 SharedMemSynchronizer* synchronizers, size_t count) | |
21 : synchronizers_(synchronizers), count_(count), last_(count - 1) { | |
22 DCHECK_GT(count, 0U); | |
23 } | |
24 | |
25 int SharedMemSynchronizer::WaitForMultiple::Wait() { | |
26 int ret = WaitMultiple(synchronizers_, count_, last_); | |
27 last_ = (ret >= 0) ? static_cast<size_t>(ret) : count_ - 1; | |
Ami GONE FROM CHROMIUM
2012/03/08 17:04:36
When will the conditional be false, given the
DCHE
tommi (sloooow) - chröme
2012/03/09 12:15:49
That DCHECK is to catch programmer error so hopefu
Ami GONE FROM CHROMIUM
2012/03/09 16:36:47
That's what the DCHECK connotes to me, as well.
tommi (sloooow) - chröme
2012/03/13 12:26:13
Done. Added CHECKs to WaitMultiple.
| |
28 return ret; | |
29 } | |
30 | |
31 SharedMemSynchronizer::SharedMemSynchronizer() {} | |
32 | |
33 #if defined(OS_POSIX) | |
34 | |
35 SharedMemSynchronizer::~SharedMemSynchronizer() {} | |
36 | |
37 SharedMemSynchronizer::SharedMemSynchronizer(IPCHandle handle_1, | |
38 IPCHandle handle_2) | |
39 : socket_(handle_1.fd) { | |
40 DCHECK_NE(handle_1.fd, -1); | |
41 DCHECK_EQ(handle_2.fd, -1); | |
42 DCHECK(IsValid()); | |
43 } | |
44 | |
45 void SharedMemSynchronizer::Signal() { | |
46 DCHECK(IsValid()); | |
47 char signal = 1; | |
48 size_t bytes = socket_.Send(&signal, sizeof(signal)); | |
Ami GONE FROM CHROMIUM
2012/03/08 17:04:36
Is this depending on the socket having a buffer so
tommi (sloooow) - chröme
2012/03/09 12:15:49
Yes, the socket will buffer the signal to satisfy
Ami GONE FROM CHROMIUM
2012/03/09 16:36:47
I suspect on posix you'll get a hang as the pipe's
tommi (sloooow) - chröme
2012/03/13 12:26:13
It doesn't block actually and there should only be
| |
49 DCHECK_EQ(bytes, 1U) << "errno: " << errno; | |
50 } | |
51 | |
52 void SharedMemSynchronizer::Wait() { | |
53 DCHECK(IsValid()); | |
54 char signal = 0; | |
55 size_t bytes = socket_.Receive(&signal, sizeof(signal)); | |
56 DCHECK_EQ(bytes, 1U) << "errno: " << errno; | |
57 DCHECK_EQ(signal, 1); | |
58 } | |
59 | |
60 bool SharedMemSynchronizer::IsValid() const { | |
61 return socket_.handle() != SocketClass::kInvalidHandle; | |
62 } | |
63 | |
64 bool SharedMemSynchronizer::ShareToProcess(base::ProcessHandle process, | |
65 IPCHandle* handle_1, | |
66 IPCHandle* handle_2) { | |
67 DCHECK(IsValid()); | |
68 handle_1->fd = socket_.handle(); | |
69 handle_1->auto_close = false; | |
70 handle_2->fd = -1; | |
71 return true; | |
72 } | |
73 | |
74 // static | |
75 bool SharedMemSynchronizer::InitializePair(SharedMemSynchronizer* a, | |
76 SharedMemSynchronizer* b) { | |
77 DCHECK(!a->IsValid()); | |
78 DCHECK(!b->IsValid()); | |
79 | |
80 bool ok = SocketClass::CreatePair(&a->socket_, &b->socket_); | |
81 | |
82 DLOG_IF(WARNING, !ok) << "failed to create socket: " << errno; | |
83 DCHECK(!ok || a->IsValid()); | |
84 DCHECK(!ok || b->IsValid()); | |
85 return ok; | |
86 } | |
87 | |
88 // static | |
89 int SharedMemSynchronizer::WaitMultiple(SharedMemSynchronizer* synchronizers, | |
90 size_t count, | |
91 size_t last_signaled) { | |
92 DCHECK_LT(last_signaled < count); | |
93 | |
94 for (size_t i = 0; i < count; ++i) { | |
95 DCHECK(synchronizers[i].IsValid()); | |
96 } | |
97 | |
98 int ret = -1; | |
99 | |
100 // Below, we always check the |revents| of the first socket in the array | |
101 // and return the index of that socket if set. This can cause sockets | |
102 // that come later in the array to starve when the first sockets are | |
103 // very busy. So to avoid the starving problem, we use the |last_signaled| | |
104 // variable to split up the array so that the last socket to be signaled | |
105 // becomes the last socket in the array and all the other sockets will have | |
106 // priority the next time WaitMultiple is called. | |
107 scoped_array<struct pollfd> sockets(new struct pollfd[count]); | |
108 memset(&sockets[0], 0, count * sizeof(sockets[0])); | |
109 size_t index = 0; | |
110 for (size_t i = last_signaled + 1; i < count; ++i) { | |
111 struct pollfd& fd = sockets[index++]; | |
112 fd.events = POLLIN; | |
113 fd.fd = synchronizers[i].socket_.handle(); | |
114 } | |
115 | |
116 for (size_t i = 0; i <= last_signaled; ++i) { | |
117 struct pollfd& fd = sockets[index++]; | |
118 fd.events = POLLIN; | |
119 fd.fd = synchronizers[i].socket_.handle(); | |
120 } | |
121 DCHECK_EQ(index, count); | |
122 | |
123 int err = poll(&sockets[0], count, -1); | |
124 if (err != -1) { | |
125 for (size_t i = 0; i < count; ++i) { | |
126 if (sockets[i].revents) { | |
127 ret = (i + last_signaled + 1) % count; | |
128 DCHECK_EQ(sockets[i].fd, synchronizers[ret].socket_.handle()); | |
129 synchronizers[ret].Wait(); | |
130 break; | |
Ami GONE FROM CHROMIUM
2012/03/08 17:04:36
could just return ret; here and replace the remain
tommi (sloooow) - chröme
2012/03/09 12:15:49
This has fewer returns and produces smaller code.
Ami GONE FROM CHROMIUM
2012/03/09 16:36:47
Yes.
tommi (sloooow) - chröme
2012/03/13 12:26:13
Done.
| |
131 } | |
132 } | |
133 } else { | |
134 NOTREACHED() << "poll() failed errno: " << errno; | |
135 } | |
136 | |
137 DCHECK_NE(ret, -1); | |
138 return ret; | |
139 } | |
140 | |
141 #endif // !defined(OS_POSIX) | |
OLD | NEW |