OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #include "platform/globals.h" | |
6 #if defined(TARGET_OS_MACOS) | |
7 | |
8 #include <errno.h> // NOLINT | |
9 #include <stdio.h> // NOLINT | |
10 #include <stdlib.h> // NOLINT | |
11 #include <string.h> // NOLINT | |
12 #include <sys/event.h> // NOLINT | |
13 #include <unistd.h> // NOLINT | |
14 | |
15 #include "bin/dartutils.h" | |
16 #include "bin/dbg_connection.h" | |
17 #include "bin/fdutils.h" | |
18 #include "bin/log.h" | |
19 #include "bin/socket.h" | |
20 #include "platform/signal_blocker.h" | |
21 #include "platform/utils.h" | |
22 | |
23 | |
24 namespace dart { | |
25 namespace bin { | |
26 | |
27 #define INVALID_FD -1 | |
28 | |
29 int DebuggerConnectionImpl::kqueue_fd_ = INVALID_FD; | |
30 int DebuggerConnectionImpl::wakeup_fds_[2] = {INVALID_FD, INVALID_FD}; | |
31 | |
32 | |
33 // Used by VM threads to send a message to the debugger connetion | |
34 // handler thread. | |
35 void DebuggerConnectionImpl::SendMessage(MessageType id) { | |
36 ASSERT(wakeup_fds_[1] != INVALID_FD); | |
37 struct Message msg; | |
38 msg.msg_id = id; | |
39 int result = FDUtils::WriteToBlocking(wakeup_fds_[1], &msg, sizeof(msg)); | |
40 if (result != sizeof(msg)) { | |
41 if (result == -1) { | |
42 perror("Wakeup message failure: "); | |
43 } | |
44 FATAL1("Wakeup message failure. Wrote %d bytes.", result); | |
45 } | |
46 } | |
47 | |
48 | |
49 // Used by the debugger connection handler to read the messages sent | |
50 // by the VM. | |
51 bool DebuggerConnectionImpl::ReceiveMessage(Message* msg) { | |
52 int total_read = 0; | |
53 int bytes_read = 0; | |
54 int remaining = sizeof(Message); | |
55 uint8_t* buf = reinterpret_cast<uint8_t*>(msg); | |
56 while (remaining > 0) { | |
57 bytes_read = | |
58 TEMP_FAILURE_RETRY(read(wakeup_fds_[0], buf + total_read, remaining)); | |
59 if ((bytes_read < 0) && (total_read == 0)) { | |
60 return false; | |
61 } | |
62 if (bytes_read > 0) { | |
63 total_read += bytes_read; | |
64 remaining -= bytes_read; | |
65 } | |
66 } | |
67 ASSERT(remaining >= 0); | |
68 return remaining == 0; | |
69 } | |
70 | |
71 | |
72 void DebuggerConnectionImpl::HandleEvent(struct kevent* event) { | |
73 intptr_t ident = event->ident; | |
74 if (ident == DebuggerConnectionHandler::listener_fd_) { | |
75 if (DebuggerConnectionHandler::IsConnected()) { | |
76 FATAL("Cannot connect to more than one debugger.\n"); | |
77 } | |
78 intptr_t fd = ServerSocket::Accept(ident); | |
79 if (fd < 0) { | |
80 FATAL("Accepting new debugger connection failed.\n"); | |
81 } | |
82 FDUtils::SetBlocking(fd); | |
83 DebuggerConnectionHandler::AcceptDbgConnection(fd); | |
84 | |
85 /* For now, don't poll the debugger connection. | |
86 struct kevent ev_add; | |
87 EV_SET(&ev_add, fd, EVFILT_READ, EV_ADD, 0, 0, NULL); | |
88 int status = | |
89 TEMP_FAILURE_RETRY(kevent(kqueue_fd_, &ev_add, 1, NULL, 0, NULL)); | |
90 if (status == -1) { | |
91 const int kBufferSize = 1024; | |
92 char error_message[kBufferSize]; | |
93 Utils::StrError(errno, error_message, kBufferSize); | |
94 FATAL1("Failed adding debugger socket to kqueue: %s\n", error_message); | |
95 } | |
96 */ | |
97 } else if (ident == wakeup_fds_[0]) { | |
98 Message msg; | |
99 if (ReceiveMessage(&msg)) { | |
100 Log::Print("Received sync message id %d.\n", msg.msg_id); | |
101 } | |
102 } else { | |
103 Log::Print("unexpected: receiving debugger connection event.\n"); | |
104 UNIMPLEMENTED(); | |
105 } | |
106 } | |
107 | |
108 | |
109 void DebuggerConnectionImpl::Handler(uword args) { | |
110 static const int kMaxEvents = 4; | |
111 struct kevent events[kMaxEvents]; | |
112 | |
113 while (1) { | |
114 // Wait indefinitely for an event. | |
115 int result = TEMP_FAILURE_RETRY( | |
116 kevent(kqueue_fd_, NULL, 0, events, kMaxEvents, NULL)); | |
117 if (result == -1) { | |
118 const int kBufferSize = 1024; | |
119 char error_message[kBufferSize]; | |
120 Utils::StrError(errno, error_message, kBufferSize); | |
121 FATAL1("kevent failed %s\n", error_message); | |
122 } else { | |
123 ASSERT(result <= kMaxEvents); | |
124 for (int i = 0; i < result; i++) { | |
125 HandleEvent(&events[i]); | |
126 } | |
127 } | |
128 } | |
129 Log::Print("shutting down debugger thread\n"); | |
130 } | |
131 | |
132 | |
133 void DebuggerConnectionImpl::SetupPollQueue() { | |
134 int result; | |
135 result = NO_RETRY_EXPECTED(pipe(wakeup_fds_)); | |
136 if (result != 0) { | |
137 FATAL1("Pipe creation failed with error %d\n", result); | |
138 } | |
139 FDUtils::SetNonBlocking(wakeup_fds_[0]); | |
140 | |
141 kqueue_fd_ = NO_RETRY_EXPECTED(kqueue()); | |
142 if (kqueue_fd_ == -1) { | |
143 FATAL("Failed creating kqueue\n"); | |
144 } | |
145 // Register the wakeup_fd_ with the kqueue. | |
146 struct kevent event; | |
147 EV_SET(&event, wakeup_fds_[0], EVFILT_READ, EV_ADD, 0, 0, NULL); | |
148 int status = NO_RETRY_EXPECTED(kevent(kqueue_fd_, &event, 1, NULL, 0, NULL)); | |
149 if (status == -1) { | |
150 const int kBufferSize = 1024; | |
151 char error_message[kBufferSize]; | |
152 Utils::StrError(errno, error_message, kBufferSize); | |
153 FATAL1("Failed adding wakeup pipe fd to kqueue: %s\n", error_message); | |
154 } | |
155 | |
156 // Register the listening socket. | |
157 EV_SET(&event, DebuggerConnectionHandler::listener_fd_, | |
158 EVFILT_READ, EV_ADD, 0, 0, NULL); | |
159 status = NO_RETRY_EXPECTED(kevent(kqueue_fd_, &event, 1, NULL, 0, NULL)); | |
160 if (status == -1) { | |
161 const int kBufferSize = 1024; | |
162 char error_message[kBufferSize]; | |
163 Utils::StrError(errno, error_message, kBufferSize); | |
164 FATAL1("Failed adding listener socket to kqueue: %s\n", error_message); | |
165 } | |
166 } | |
167 | |
168 | |
169 void DebuggerConnectionImpl::StartHandler(int port_number) { | |
170 ASSERT(DebuggerConnectionHandler::listener_fd_ != -1); | |
171 SetupPollQueue(); | |
172 int result = Thread::Start(&DebuggerConnectionImpl::Handler, 0); | |
173 if (result != 0) { | |
174 FATAL1("Failed to start debugger connection handler thread: %d\n", result); | |
175 } | |
176 } | |
177 | |
178 | |
179 intptr_t DebuggerConnectionImpl::Send(intptr_t socket, | |
180 const char* buf, | |
181 int len) { | |
182 return TEMP_FAILURE_RETRY(write(socket, buf, len)); | |
183 } | |
184 | |
185 | |
186 intptr_t DebuggerConnectionImpl::Receive(intptr_t socket, char* buf, int len) { | |
187 return TEMP_FAILURE_RETRY(read(socket, buf, len)); | |
188 } | |
189 | |
190 } // namespace bin | |
191 } // namespace dart | |
192 | |
193 #endif // defined(TARGET_OS_MACOS) | |
OLD | NEW |