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

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: 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
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 "bin/fdutils.h"
8 #include "bin/file.h"
9 #include "bin/platform.h"
10 #include "bin/socket.h"
11 #include "bin/thread.h"
12 #include "include/dart_debugger_api.h"
13 #include "platform/json.h"
14
15 namespace dart {
16
17 #define BUFSIZE 8192
18
19 // Global static pointer used to ensure a single instance of the class.
20 VmStats* VmStats::instance_ = NULL;
21 Mutex VmStats::instance_lock_;
22
23 void VmStats::Start(int port, const char* root_dir) {
24 if (instance_ != NULL) {
siva 2013/02/15 05:59:10 Where is instance_ set? I don't see it being set t
Tom Ball 2013/02/16 00:57:19 It was the last statement in Start(), but I change
25 FATAL("VmStats already started.");
26 }
27 MutexLocker ml(&instance_lock_);
28 VmStats* vmstats = new VmStats;
siva 2013/02/15 05:59:10 probably you meant instance_ = new VmStats(); here
Tom Ball 2013/02/16 00:57:19 Done.
29 VmStatusService::InitOnce();
30 Socket::Initialize();
31
32 if (root_dir != NULL) {
33 vmstats->root_directory_ = root_dir;
34 }
35
36 const intptr_t BACKLOG = 128; // Default value from HttpServer.dart
37 intptr_t bind_address =
38 ServerSocket::CreateBindListen("127.0.0.1", port, BACKLOG);
39 if (bind_address < 0) {
40 fprintf(stderr, "Failed binding VmStats socket: 127.0.0.1:%d\n", port);
41 return;
42 }
siva 2013/02/15 05:59:10 If port is -1 we probably need code here to get th
Tom Ball 2013/02/16 00:57:19 Done.
43 int errno = Thread::Start(WebServer, bind_address);
44 if (errno != 0) {
45 fprintf(stderr, "Failed starting VmStats thread: %d\n", errno);
46 return;
47 }
48 instance_ = vmstats;
49 }
50
51
52 void VmStats::Stop() {
53 MutexLocker ml(&instance_lock_);
54 if (instance_ != NULL) {
55 delete instance_;
siva 2013/02/15 05:59:10 The WebServer thread is still running and it acces
Tom Ball 2013/02/16 00:57:19 Reworked stop so it only sets a running_ instance
56 instance_ = NULL;
57 }
58 }
59
60
61 void VmStats::AddIsolate(IsolateData* isolate_data,
62 Dart_Isolate isolate) {
63 MutexLocker ml(&instance_lock_);
64 if (instance_ != NULL) {
65 instance_->isolate_table_[isolate_data] = isolate;
66 }
67 }
68
69
70 void VmStats::RemoveIsolate(IsolateData* isolate_data) {
71 MutexLocker ml(&instance_lock_);
72 if (instance_ != NULL) {
73 instance_->isolate_table_.erase(isolate_data);
74 }
75 }
76
77
78 static bool endsWith(const std::string s, const char* ending) {
79 size_t ending_len = strlen(ending);
80 if (s.length() > ending_len) {
81 return s.compare(s.length() - ending_len, ending_len, ending) == 0;
82 } else {
83 return false;
84 }
85 }
86
87
88 static const char* ContentType(const char* url) {
89 // TODO(tball): replace with static map?
90 std::string path(url);
siva 2013/02/15 05:59:10 might be more efficient to just do a const char* s
Tom Ball 2013/02/16 00:57:19 Done.
91 if (endsWith(path, ".html")) {
92 return "text/html; charset=UTF-8";
93 }
94 if (endsWith(path, ".dart")) {
95 return "application/dart; charset=UTF-8";
96 }
97 if (endsWith(path, ".js")) {
98 return "application/javascript; charset=UTF-8";
99 }
100 if (endsWith(path, ".css")) {
101 return "text/css; charset=UTF-8";
102 }
103 if (endsWith(path, ".gif")) {
104 return "image/gif";
105 }
106 if (endsWith(path, ".png")) {
107 return "image/png";
108 }
109 if (endsWith(path, ".jpg") || endsWith(path, ".jpeg")) {
110 return "image/jpeg";
111 }
112 return "text/plain";
113 }
114
115
116 void VmStats::WebServer(uword bind_address) {
117 while (true) {
118 intptr_t socket = ServerSocket::Accept(bind_address);
119 if (socket == ServerSocket::kTemporaryFailure) {
120 // Not a real failure, woke up but no connection available.
121 sleep(1);
122 continue;
123 }
124 if (socket < 0) {
125 FATAL("Accepting new web server connection failed.\n");
126 }
127 FDUtils::SetBlocking(socket);
128
129 // TODO(tball): rewrite this to use STL, so as to eliminate the static
130 // buffer and support resources that are bigger than BUFSIZE.
131
132 // Read request.
133 static char buffer[BUFSIZE + 1];
134 int len = read(socket, buffer, BUFSIZE);
siva 2013/02/15 05:59:10 We may need to handle partial reads here but let u
Tom Ball 2013/02/16 00:57:19 This buffer works as long as the server only suppo
135 if (len <= 0) {
136 // Invalid HTTP request, ignore.
137 continue;
138 }
139 buffer[len] = '\0';
140
141 // Verify it's a GET request.
142 if (strncmp("GET ", buffer, 4) != 0 && strncmp("get ", buffer, 4) != 0) {
143 fprintf(stderr, "Unsupported HTTP request type");
144 const char* response = "HTTP/1.1 403 Forbidden\n"
145 "Content-Length: 120\n"
146 "Connection: close\n"
147 "Content-Type: text/html\n\n"
148 "<html><head>\n<title>403 Forbidden</title>\n</head>"
149 "<body>\n<h1>Forbidden</h1>\nUnsupported HTTP request type\n</body>"
150 "</html>\n";
151 Socket::Write(socket, response, strlen(response));
siva 2013/02/15 05:59:10 Does Socket::Write assert that the entire buffer p
Tom Ball 2013/02/16 00:57:19 It does because I previously set the socket to blo
152 close(socket);
siva 2013/02/15 05:59:10 Socket::Close(socket); ?
Tom Ball 2013/02/16 00:57:19 Done.
153 continue;
154 }
155
156 // Extract GET URL, and null-terminate URL in case request line has
157 // HTTP version.
158 for (int i = 4; i < len; i++) {
159 if (buffer[i] == ' ') {
160 buffer[i] = '\0';
161 }
162 }
163 char* url = &buffer[4];
164 printf("vmstats: %s requested\n", url);
165 char* content = NULL;
166
167 // Check for VmStats-specific URLs.
168 if (strcmp(url, "/isolates") == 0) {
169 content = instance_->IsolatesStatus();
170 } else {
171 // Check plug-ins.
172 content = VmStatusService::GetVmStatus(url);
173 }
174
175 if (content != NULL) {
176 size_t content_len = strlen(content);
177 len = snprintf(buffer, BUFSIZE-1,
178 "HTTP/1.1 200 OK\nContent-Type: application/json; charset=UTF-8\n"
179 "Content-Length: %d\n\n", content_len);
180 Socket::Write(socket, buffer, strlen(buffer));
181 Socket::Write(socket, content, content_len);
182 Socket::Write(socket, "\n", 1);
183 Socket::Write(socket, buffer, strlen(buffer));
184 free(content);
185 } else {
186 // No status content with this URL, return file or resource content.
187 std::string path(instance_->root_directory_);
188 path.append(url);
189 bool success = false;
190 if (File::Exists(path.c_str())) {
191 File* f = File::Open(path.c_str(), File::kRead);
192 if (f != NULL) {
193 intptr_t len = f->Length();
194 char* text_buffer = reinterpret_cast<char*>(malloc(len));
195 if (f->ReadFully(text_buffer, len)) {
196 std::string content(text_buffer, len);
197 const char* content_type = ContentType(url);
198 len = snprintf(buffer, BUFSIZE-1,
199 "HTTP/1.1 200 OK\nContent-Type: %s\n"
200 "Content-Length: %d\n\n",
201 content_type, static_cast<int>(content.length()));
202 Socket::Write(socket, buffer, strlen(buffer));
203 Socket::Write(socket, content.c_str(), content.length());
204 Socket::Write(socket, "\n", 1);
205 success = true;
206 }
207 free(text_buffer);
208 delete f;
209 }
210 } else {
211 // TODO(tball): look up linked in resource.
212 }
213 if (!success) {
214 const char* response = "HTTP/1.1 404 Not Found\n\n";
215 Socket::Write(socket, response, strlen(response));
216 }
217 }
218 Socket::Close(socket);
219 }
220 }
221
222
223 char* VmStats::IsolatesStatus() {
224 std::ostringstream stream;
225 stream << '{' << std::endl;
226 stream << "\"isolates\": [" << std::endl;
227 IsolateTable::iterator itr;
228 bool first = true;
229 for (itr = isolate_table_.begin(); itr != isolate_table_.end(); ++itr) {
230 Dart_Isolate isolate = itr->second;
231 static char request[512];
232 snprintf(request, sizeof(request), "/isolate/0x%llx",
233 reinterpret_cast<int64_t>(isolate));
234 char* status = VmStatusService::GetVmStatus(request);
235 if (status != NULL) {
236 stream << status;
237 if (!first) {
238 stream << "," << std::endl;
239 }
240 first = false;
241 }
242 free(status);
243 }
244 stream << std::endl << "]";
245 stream << std::endl << '}' << std::endl;
246 return strdup(stream.str().c_str());
247 }
248
249
250 // Global static pointer used to ensure a single instance of the class.
251 VmStatusService* VmStatusService::instance_ = NULL;
252
253
254 void VmStatusService::InitOnce() {
siva 2013/02/15 05:59:10 ASSERT(VmStatusService::Instance_ == NULL);
Tom Ball 2013/02/16 00:57:19 Done.
255 VmStatusService::instance_ = new VmStatusService();
256
257 // Register built-in status plug-ins. RegisterPlugin is not used because
258 // this isn't called within an isolate, and because parameter checking
259 // isn't necessary.
260 instance_->RegisterPlugin(&Dart_GetVmStatus);
261
262 // TODO(tball): dynamically load any additional plug-ins.
263 }
264
265
266 int VmStatusService::RegisterPlugin(Dart_VmStatusCallback callback) {
siva 2013/02/15 05:59:10 We should probably protect this call also under a
Tom Ball 2013/02/16 00:57:19 Done.
267 if (callback == NULL) {
268 return -1;
269 }
270 VmStatusPlugin* plugin = new VmStatusPlugin(callback);
271 VmStatusPlugin* list = instance_->registered_plugin_list_;
272 if (list == NULL) {
273 instance_->registered_plugin_list_ = plugin;
274 } else {
275 list->Append(plugin);
276 }
277 return 0;
278 }
279
280
281 char* VmStatusService::GetVmStatus(const char* request) {
282 VmStatusPlugin* plugin = instance_->registered_plugin_list_;
283 while (plugin != NULL) {
284 char* result = (plugin->callback())(request);
285 if (result != NULL) {
286 return result;
287 }
288 plugin = plugin->next();
289 }
290 return NULL;
291 }
292
293 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698