OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library vmservice; | 5 library vmservice; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:convert'; | 8 import 'dart:convert'; |
9 import 'dart:isolate'; | 9 import 'dart:isolate'; |
| 10 import 'dart:typed_data'; |
10 | 11 |
11 part 'client.dart'; | 12 part 'client.dart'; |
12 part 'constants.dart'; | 13 part 'constants.dart'; |
13 part 'running_isolate.dart'; | 14 part 'running_isolate.dart'; |
14 part 'running_isolates.dart'; | 15 part 'running_isolates.dart'; |
15 part 'message.dart'; | 16 part 'message.dart'; |
16 part 'message_router.dart'; | 17 part 'message_router.dart'; |
17 | 18 |
18 final RawReceivePort isolateLifecyclePort = new RawReceivePort(); | 19 final RawReceivePort isolateLifecyclePort = new RawReceivePort(); |
19 final RawReceivePort scriptLoadPort = new RawReceivePort(); | 20 final RawReceivePort scriptLoadPort = new RawReceivePort(); |
20 | 21 |
21 typedef ShutdownCallback(); | 22 typedef ShutdownCallback(); |
22 | 23 |
23 class VMService extends MessageRouter { | 24 class VMService extends MessageRouter { |
24 static VMService _instance; | 25 static VMService _instance; |
| 26 |
25 /// Collection of currently connected clients. | 27 /// Collection of currently connected clients. |
26 final Set<Client> clients = new Set<Client>(); | 28 final Set<Client> clients = new Set<Client>(); |
27 | 29 |
28 // A map encoding which clients are interested in which kinds of events. | |
29 final Map<int, Set<Client>> eventMap = new Map<int, Set<Client>>(); | |
30 | |
31 /// Collection of currently running isolates. | 30 /// Collection of currently running isolates. |
32 RunningIsolates runningIsolates = new RunningIsolates(); | 31 RunningIsolates runningIsolates = new RunningIsolates(); |
33 | 32 |
34 /// A port used to receive events from the VM. | 33 /// A port used to receive events from the VM. |
35 final RawReceivePort eventPort; | 34 final RawReceivePort eventPort; |
36 | 35 |
37 ShutdownCallback onShutdown; | 36 ShutdownCallback onShutdown; |
38 | 37 |
39 void _addClient(Client client) { | 38 void _addClient(Client client) { |
40 clients.add(client); | 39 clients.add(client); |
41 } | 40 } |
42 | 41 |
43 void _removeClient(Client client) { | 42 void _removeClient(Client client) { |
44 clients.remove(client); | 43 clients.remove(client); |
45 } | 44 } |
46 | 45 |
47 int eventTypeCode(String eventType) { | 46 void _eventMessageHandler(dynamic eventMessage) { |
48 switch(eventType) { | 47 for (var client in clients) { |
49 case 'debug': | 48 if (client.sendEvents) { |
50 return Constants.EVENT_FAMILY_DEBUG; | 49 client.post(null, eventMessage); |
51 case 'gc': | 50 } |
52 return Constants.EVENT_FAMILY_GC; | |
53 default: | |
54 return -1; | |
55 } | 51 } |
56 } | 52 } |
57 | 53 |
58 void _updateEventMask() { | |
59 int mask = 0; | |
60 for (var key in eventMap.keys) { | |
61 var subscribers = eventMap[key]; | |
62 if (subscribers.isNotEmpty) { | |
63 mask |= (1 << key); | |
64 } | |
65 } | |
66 _setEventMask(mask); | |
67 } | |
68 | |
69 void subscribe(String eventType, Client client) { | |
70 int eventCode = eventTypeCode(eventType); | |
71 assert(eventCode >= 0); | |
72 var subscribers = eventMap.putIfAbsent(eventCode, () => new Set<Client>()); | |
73 subscribers.add(client); | |
74 _updateEventMask(); | |
75 } | |
76 | |
77 void _controlMessageHandler(int code, | 54 void _controlMessageHandler(int code, |
78 int port_id, | 55 int portId, |
79 SendPort sp, | 56 SendPort sp, |
80 String name) { | 57 String name) { |
81 switch (code) { | 58 switch (code) { |
82 case Constants.ISOLATE_STARTUP_MESSAGE_ID: | 59 case Constants.ISOLATE_STARTUP_MESSAGE_ID: |
83 runningIsolates.isolateStartup(port_id, sp, name); | 60 runningIsolates.isolateStartup(portId, sp, name); |
84 break; | 61 break; |
85 case Constants.ISOLATE_SHUTDOWN_MESSAGE_ID: | 62 case Constants.ISOLATE_SHUTDOWN_MESSAGE_ID: |
86 runningIsolates.isolateShutdown(port_id, sp); | 63 runningIsolates.isolateShutdown(portId, sp); |
87 break; | 64 break; |
88 } | 65 } |
89 } | 66 } |
90 | 67 |
91 void _eventMessageHandler(int eventType, dynamic eventMessage) { | |
92 var subscribers = eventMap[eventType]; | |
93 if (subscribers == null) { | |
94 return; | |
95 } | |
96 for (var subscriber in subscribers) { | |
97 subscriber.post(null, eventMessage); | |
98 } | |
99 } | |
100 | |
101 void _exit() { | 68 void _exit() { |
102 if (onShutdown != null) { | 69 if (onShutdown != null) { |
103 onShutdown(); | 70 onShutdown(); |
104 } | 71 } |
105 isolateLifecyclePort.close(); | 72 isolateLifecyclePort.close(); |
106 scriptLoadPort.close(); | 73 scriptLoadPort.close(); |
107 var clientList = clients.toList(); | 74 for (var client in clients) { |
108 for (var client in clientList) { | |
109 client.close(); | 75 client.close(); |
110 } | 76 } |
111 _onExit(); | 77 _onExit(); |
112 } | 78 } |
113 | 79 |
114 void messageHandler(message) { | 80 void messageHandler(message) { |
115 assert(message is List); | 81 if (message is String) { |
116 if (message is List && (message.length == 4)) { | 82 // This is an event intended for all clients. |
117 _controlMessageHandler(message[0], message[1], message[2], message[3]); | 83 _eventMessageHandler(message); |
118 } else if (message is List && (message.length == 2)) { | 84 return; |
119 _eventMessageHandler(message[0], message[1]); | |
120 } else if (message is List && (message.length == 1)) { | |
121 assert(message[0] == Constants.SERVICE_EXIT_MESSAGE_ID); | |
122 _exit(); | |
123 } else { | |
124 Logger.root.severe('Unexpected message: $message'); | |
125 } | 85 } |
| 86 if (message is Uint8List) { |
| 87 // This is "raw" data intended for a specific client. |
| 88 // |
| 89 // TODO(turnidge): Do not broadcast this data to all clients. |
| 90 _eventMessageHandler(message); |
| 91 return; |
| 92 } |
| 93 if (message is List) { |
| 94 // This is an internal vm service event. |
| 95 if (message.length == 1) { |
| 96 // This is a control message directing the vm service to exit. |
| 97 assert(message[0] == Constants.SERVICE_EXIT_MESSAGE_ID); |
| 98 _exit(); |
| 99 return; |
| 100 } |
| 101 if (message.length == 4) { |
| 102 // This is a message informing us of the birth or death of an |
| 103 // isolate. |
| 104 _controlMessageHandler(message[0], message[1], message[2], message[3]); |
| 105 return; |
| 106 } |
| 107 } |
| 108 |
| 109 Logger.root.severe( |
| 110 'Internal vm-service error: ignoring illegal message: $message'); |
126 } | 111 } |
127 | 112 |
128 void _notSupported(_) { | 113 void _notSupported(_) { |
129 throw new UnimplementedError('Service script loading not supported.'); | 114 throw new UnimplementedError('Service script loading not supported.'); |
130 } | 115 } |
131 | 116 |
132 VMService._internal() | 117 VMService._internal() |
133 : eventPort = isolateLifecyclePort { | 118 : eventPort = isolateLifecyclePort { |
134 scriptLoadPort.handler = _notSupported; | 119 scriptLoadPort.handler = _notSupported; |
135 eventPort.handler = messageHandler; | 120 eventPort.handler = messageHandler; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 RawReceivePort boot() { | 158 RawReceivePort boot() { |
174 // Return the port we expect isolate startup and shutdown messages on. | 159 // Return the port we expect isolate startup and shutdown messages on. |
175 return isolateLifecyclePort; | 160 return isolateLifecyclePort; |
176 } | 161 } |
177 | 162 |
178 void _registerIsolate(int port_id, SendPort sp, String name) { | 163 void _registerIsolate(int port_id, SendPort sp, String name) { |
179 var service = new VMService(); | 164 var service = new VMService(); |
180 service.runningIsolates.isolateStartup(port_id, sp, name); | 165 service.runningIsolates.isolateStartup(port_id, sp, name); |
181 } | 166 } |
182 | 167 |
183 void _setEventMask(int mask) | |
184 native "VMService_SetEventMask"; | |
185 | |
186 void _onStart() native "VMService_OnStart"; | 168 void _onStart() native "VMService_OnStart"; |
187 | 169 |
188 void _onExit() native "VMService_OnExit"; | 170 void _onExit() native "VMService_OnExit"; |
OLD | NEW |