Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Side by Side Diff: runtime/bin/vmstats_impl.cc

Issue 12221022: Initial prototype of vmstats support, based on Dart VM Stats draft design doc. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Code review feedback response Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/vmstats_impl.h ('k') | runtime/include/dart_debugger_api.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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 "bin/vmstats_impl.h"
6
7 #include <sstream>
8
9 #include "bin/fdutils.h"
10 #include "bin/file.h"
11 #include "bin/log.h"
12 #include "bin/platform.h"
13 #include "bin/socket.h"
14 #include "bin/thread.h"
15 #include "bin/utils.h"
16 #include "include/dart_debugger_api.h"
17 #include "platform/json.h"
18
19 namespace dart {
20
21 #define BUFSIZE 8192
22
23 static const char* INDEX_HTML = "index.html";
24 static const char* VMSTATS_HTML = "vmstats.html";
25 static const char* DEFAULT_HOST = "localhost";
26
27 // Global static pointer used to ensure a single instance of the class.
28 VmStats* VmStats::instance_ = NULL;
29 Monitor VmStats::instance_monitor_;
30 Mutex VmStatusService::mutex_;
31
32
33 void VmStats::Start(int port, const char* root_dir) {
34 if (instance_ != NULL) {
35 FATAL("VmStats already started.");
36 }
37 MonitorLocker ml(&instance_monitor_);
38 instance_ = new VmStats();
39 VmStatusService::InitOnce();
40 Socket::Initialize();
41
42 if (root_dir != NULL) {
43 instance_->root_directory_ = root_dir;
44 }
45
46 // TODO(tball): allow host to be specified.
47 char* host = const_cast<char*>(DEFAULT_HOST);
48 OSError* os_error;
49 const char* host_ip = Socket::LookupIPv4Address(host, &os_error);
50 if (host_ip == NULL) {
51 Log::PrintErr("Failed IP lookup of VmStats host %s: %s\n",
52 host, os_error->message());
53 return;
54 }
55
56 const intptr_t BACKLOG = 128; // Default value from HttpServer.dart
57 int64_t address = ServerSocket::CreateBindListen(host_ip, port, BACKLOG);
58 if (address < 0) {
59 Log::PrintErr("Failed binding VmStats socket: %s:%d\n", host, port);
60 return;
61 }
62 Log::Print("VmStats URL: http://%s:%d/\n", host,
63 Socket::GetPort(address));
64
65 instance_->running_ = true;
66 int errno = Thread::Start(WebServer, address);
siva 2013/02/25 06:47:41 Where is the server socket represented by address
Tom Ball 2013/02/26 21:50:49 Saved bind_address to instance, closed in VmStats:
67 if (errno != 0) {
68 Log::PrintErr("Failed starting VmStats thread: %d\n", errno);
69 Shutdown();
70 }
71 }
72
73
74 void VmStats::Stop() {
siva 2013/02/25 06:47:41 Need MonitorLocker ml&instance_monitor_); here as
Tom Ball 2013/02/26 21:50:49 Done.
75 if (instance_ != NULL) {
76 instance_->running_ = false;
77 }
78 }
79
80
81 void VmStats::Shutdown() {
82 MonitorLocker ml(&instance_monitor_);
83 delete instance_;
84 instance_ = NULL;
85 }
86
87
88 void VmStats::AddIsolate(IsolateData* isolate_data,
89 Dart_Isolate isolate) {
90 MonitorLocker ml(&instance_monitor_);
91 if (instance_ != NULL) {
92 instance_->isolate_table_[isolate_data] = isolate;
93 }
94 }
95
96
97 void VmStats::RemoveIsolate(IsolateData* isolate_data) {
98 MonitorLocker ml(&instance_monitor_);
99 if (instance_ != NULL) {
100 instance_->isolate_table_.erase(isolate_data);
101 }
102 }
103
104
105 static const char* ContentType(const char* url) {
106 const char* suffix = strrchr(url, '.');
107 if (suffix != NULL) {
108 if (!strcmp(suffix, ".html")) {
109 return "text/html; charset=UTF-8";
110 }
111 if (!strcmp(suffix, ".dart")) {
112 return "application/dart; charset=UTF-8";
113 }
114 if (!strcmp(suffix, ".js")) {
115 return "application/javascript; charset=UTF-8";
116 }
117 if (!strcmp(suffix, ".css")) {
118 return "text/css; charset=UTF-8";
119 }
120 if (!strcmp(suffix, ".gif")) {
121 return "image/gif";
122 }
123 if (!strcmp(suffix, ".png")) {
124 return "image/png";
125 }
126 if (!strcmp(suffix, ".jpg") || !strcmp(suffix, ".jpeg")) {
127 return "image/jpeg";
128 }
129 }
130 return "text/plain";
131 }
132
133
134 void VmStats::WebServer(uword bind_address) {
135 while (instance_->running_) {
136 MonitorLocker ml(&instance_monitor_);
siva 2013/02/25 06:47:41 This should be outside the while? otherwise you wo
Tom Ball 2013/02/26 21:50:49 On 2013/02/25 06:47:41, siva wrote: As discussed,
137 intptr_t socket = ServerSocket::Accept(bind_address);
138 if (socket == ServerSocket::kTemporaryFailure) {
139 // Not a real failure, woke up but no connection available.
140 ml.Wait(100);
141 continue;
142 }
143 if (socket < 0) {
144 // Stop() closed the socket.
145 return;
146 }
147 FDUtils::SetBlocking(socket);
148
149 // TODO(tball): rewrite this to use STL, so as to eliminate the static
150 // buffer and support resource URLs that are longer than BUFSIZE.
151
152 // Read request.
153 // TODO(tball): support partial reads, possibly needed for POST uploads.
154 char buffer[BUFSIZE + 1];
155 int len = read(socket, buffer, BUFSIZE);
156 if (len <= 0) {
157 // Invalid HTTP request, ignore.
158 continue;
159 }
160 buffer[len] = '\0';
161
162 // Verify it's a GET request.
163 // TODO(tball): support POST requests.
164 if (strncmp("GET ", buffer, 4) != 0 && strncmp("get ", buffer, 4) != 0) {
165 Log::PrintErr("Unsupported HTTP request type");
166 const char* response = "HTTP/1.1 403 Forbidden\n"
167 "Content-Length: 120\n"
168 "Connection: close\n"
169 "Content-Type: text/html\n\n"
170 "<html><head>\n<title>403 Forbidden</title>\n</head>"
171 "<body>\n<h1>Forbidden</h1>\nUnsupported HTTP request type\n</body>"
172 "</html>\n";
173 Socket::Write(socket, response, strlen(response));
174 Socket::Close(socket);
175 continue;
176 }
177
178 // Extract GET URL, and null-terminate URL in case request line has
179 // HTTP version.
180 for (int i = 4; i < len; i++) {
181 if (buffer[i] == ' ') {
182 buffer[i] = '\0';
183 }
184 }
185 char* url = &buffer[4];
186
187 Log::Print("vmstats: %s requested\n", url);
188 char* content = NULL;
189
190 // Check for VmStats-specific URLs.
191 if (strcmp(url, "/isolates") == 0) {
192 content = instance_->IsolatesStatus();
193 } else {
194 // Check plug-ins.
195 content = VmStatusService::GetVmStatus(url);
196 }
197
198 if (content != NULL) {
199 size_t content_len = strlen(content);
200 len = snprintf(buffer, BUFSIZE,
201 "HTTP/1.1 200 OK\nContent-Type: application/json; charset=UTF-8\n"
202 "Content-Length: %d\n\n", content_len);
203 Socket::Write(socket, buffer, strlen(buffer));
204 Socket::Write(socket, content, content_len);
205 Socket::Write(socket, "\n", 1);
206 Socket::Write(socket, buffer, strlen(buffer));
207 free(content);
208 } else {
209 // No status content with this URL, return file or resource content.
210 std::string path(instance_->root_directory_);
211 path.append(url);
212
213 // Expand directory URLs.
214 if (strcmp(url, "/") == 0) {
215 path.append(VMSTATS_HTML);
216 } else if (url[strlen(url) - 1] == '/') {
217 path.append(INDEX_HTML);
218 }
219
220 bool success = false;
221 if (File::Exists(path.c_str())) {
222 File* f = File::Open(path.c_str(), File::kRead);
223 if (f != NULL) {
224 intptr_t len = f->Length();
225 char* text_buffer = reinterpret_cast<char*>(malloc(len));
226 if (f->ReadFully(text_buffer, len)) {
227 const char* content_type = ContentType(path.c_str());
228 snprintf(buffer, BUFSIZE,
229 "HTTP/1.1 200 OK\nContent-Type: %s\n"
230 "Content-Length: %d\n\n",
231 content_type, len);
232 Socket::Write(socket, buffer, strlen(buffer));
233 Socket::Write(socket, text_buffer, len);
234 Socket::Write(socket, "\n", 1);
235 success = true;
236 }
237 free(text_buffer);
238 delete f;
239 }
240 } else {
241 // TODO(tball): look up linked in resource.
242 }
243 if (!success) {
244 const char* response = "HTTP/1.1 404 Not Found\n\n";
245 Socket::Write(socket, response, strlen(response));
246 }
247 }
248 Socket::Close(socket);
249 }
250
251 Shutdown();
252 }
253
254
255 char* VmStats::IsolatesStatus() {
256 std::ostringstream stream;
257 stream << '{' << std::endl;
258 stream << "\"isolates\": [" << std::endl;
259 IsolateTable::iterator itr;
260 bool first = true;
261 for (itr = isolate_table_.begin(); itr != isolate_table_.end(); ++itr) {
262 Dart_Isolate isolate = itr->second;
263 static char request[512];
264 snprintf(request, sizeof(request), "/isolate/0x%llx",
265 reinterpret_cast<int64_t>(isolate));
266 char* status = VmStatusService::GetVmStatus(request);
267 if (status != NULL) {
268 stream << status;
269 if (!first) {
270 stream << "," << std::endl;
271 }
272 first = false;
273 }
274 free(status);
275 }
276 stream << std::endl << "]";
277 stream << std::endl << '}' << std::endl;
278 return strdup(stream.str().c_str());
279 }
280
281
282 // Global static pointer used to ensure a single instance of the class.
283 VmStatusService* VmStatusService::instance_ = NULL;
284
285
286 void VmStatusService::InitOnce() {
287 ASSERT(VmStatusService::instance_ == NULL);
288 VmStatusService::instance_ = new VmStatusService();
289
290 // Register built-in status plug-ins. RegisterPlugin is not used because
291 // this isn't called within an isolate, and because parameter checking
292 // isn't necessary.
293 instance_->RegisterPlugin(&Dart_GetVmStatus);
294
295 // TODO(tball): dynamically load any additional plug-ins.
296 }
297
298
299 int VmStatusService::RegisterPlugin(Dart_VmStatusCallback callback) {
300 MutexLocker ml(&mutex_);
301 if (callback == NULL) {
302 return -1;
303 }
304 VmStatusPlugin* plugin = new VmStatusPlugin(callback);
305 VmStatusPlugin* list = instance_->registered_plugin_list_;
306 if (list == NULL) {
307 instance_->registered_plugin_list_ = plugin;
308 } else {
309 list->Append(plugin);
310 }
311 return 0;
312 }
313
314
315 char* VmStatusService::GetVmStatus(const char* request) {
316 VmStatusPlugin* plugin = instance_->registered_plugin_list_;
317 while (plugin != NULL) {
318 char* result = (plugin->callback())(request);
319 if (result != NULL) {
320 return result;
321 }
322 plugin = plugin->next();
323 }
324 return NULL;
325 }
326
327 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/bin/vmstats_impl.h ('k') | runtime/include/dart_debugger_api.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698