-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
isolate.dart
777 lines (732 loc) · 33.2 KB
/
isolate.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// Concurrent programming using _isolates_:
/// independent workers that are similar to threads
/// but don't share memory,
/// communicating only via messages.
///
/// To use this library in your code:
/// ```dart
/// import 'dart:isolate';
/// ```
/// {@category VM}
library dart.isolate;
import "dart:async";
import "dart:_internal" show Since;
import "dart:typed_data" show ByteBuffer, TypedData, Uint8List;
part "capability.dart";
/// Thrown when an isolate cannot be created.
class IsolateSpawnException implements Exception {
/// Error message reported by the spawn operation.
final String message;
@pragma("vm:entry-point")
IsolateSpawnException(this.message);
String toString() => "IsolateSpawnException: $message";
}
/// An isolated Dart execution context.
///
/// All Dart code runs in an isolate, and code can access classes and values
/// only from the same isolate. Different isolates can communicate by sending
/// values through ports (see [ReceivePort], [SendPort]).
///
/// An `Isolate` object is a reference to an isolate, usually different from
/// the current isolate.
/// It represents, and can be used to control, the other isolate.
///
/// When spawning a new isolate, the spawning isolate receives an `Isolate`
/// object representing the new isolate when the spawn operation succeeds.
///
/// Isolates run code in its own event loop, and each event may run smaller tasks
/// in a nested microtask queue.
///
/// An `Isolate` object allows other isolates to control the event loop
/// of the isolate that it represents, and to inspect the isolate,
/// for example by pausing the isolate or by getting events when the isolate
/// has an uncaught error.
///
/// The [controlPort] identifies and gives access to controlling the isolate,
/// and the [pauseCapability] and [terminateCapability] guard access
/// to some control operations.
/// For example, calling [pause] on an `Isolate` object created without a
/// [pauseCapability], has no effect.
///
/// The `Isolate` object provided by a spawn operation will have the
/// control port and capabilities needed to control the isolate.
/// New isolate objects can be created without some of these capabilities
/// if necessary, using the [Isolate.Isolate] constructor.
///
/// An `Isolate` object cannot be sent over a `SendPort`, but the control port
/// and capabilities can be sent, and can be used to create a new functioning
/// `Isolate` object in the receiving port's isolate.
class Isolate {
/// Argument to `ping` and `kill`: Ask for immediate action.
static const int immediate = 0;
/// Argument to `ping` and `kill`: Ask for action before the next event.
static const int beforeNextEvent = 1;
/// Control port used to send control messages to the isolate.
///
/// The control port identifies the isolate.
///
/// An `Isolate` object allows sending control messages
/// through the control port.
///
/// Some control messages require a specific capability to be passed along
/// with the message (see [pauseCapability] and [terminateCapability]),
/// otherwise the message is ignored by the isolate.
final SendPort controlPort;
/// Capability granting the ability to pause the isolate.
///
/// This capability is required by [pause].
/// If the capability is `null`, or if it is not the correct pause capability
/// of the isolate identified by [controlPort],
/// then calls to [pause] will have no effect.
///
/// If the isolate is spawned in a paused state, use this capability as
/// argument to the [resume] method in order to resume the paused isolate.
final Capability? pauseCapability;
/// Capability granting the ability to terminate the isolate.
///
/// This capability is required by [kill] and [setErrorsFatal].
/// If the capability is `null`, or if it is not the correct termination
/// capability of the isolate identified by [controlPort],
/// then calls to those methods will have no effect.
final Capability? terminateCapability;
/// The name of the [Isolate] displayed for debug purposes.
///
/// This can be set using the `debugName` parameter in [spawn] and [spawnUri].
///
/// This name does not uniquely identify an isolate. Multiple isolates in the
/// same process may have the same `debugName`.
///
/// For a given isolate, this value will be the same as the values returned by
/// `Dart_DebugName` in the C embedding API and the `debugName` property in
/// [IsolateMirror].
@Since("2.3")
external String? get debugName;
/// Creates a new [Isolate] object with a restricted set of capabilities.
///
/// The port should be a control port for an isolate, as taken from
/// another `Isolate` object.
///
/// The capabilities should be the subset of the capabilities that are
/// available to the original isolate.
/// Capabilities of an isolate are locked to that isolate, and have no effect
/// anywhere else, so the capabilities should come from the same isolate as
/// the control port.
///
/// Can also be used to create an [Isolate] object from a control port, and
/// any available capabilities, that have been sent through a [SendPort].
///
/// Example:
/// ```dart
/// Isolate isolate = findSomeIsolate();
/// Isolate restrictedIsolate = Isolate(isolate.controlPort);
/// untrustedCode(restrictedIsolate);
/// ```
/// This example creates a new `Isolate` object that cannot be used to
/// pause or terminate the isolate. All the untrusted code can do is to
/// inspect the isolate and see uncaught errors or when it terminates.
Isolate(this.controlPort, {this.pauseCapability, this.terminateCapability});
/// An [Isolate] object representing the current isolate.
///
/// The current isolate for code using [current]
/// is the isolate running the code.
///
/// The isolate object provides the capabilities required to inspect,
/// pause or kill the isolate, and allows granting these capabilities
/// to others.
///
/// It is possible to pause the current isolate, but doing so *without*
/// first passing the ability to resume it again to another isolate,
/// is a sure way to hang your program.
external static Isolate get current;
/// The package root of the current isolate, if any.
///
/// This getter returns `null`, as the `packages/` directory is not supported
/// in Dart 2.
@Deprecated('packages/ directory resolution is not supported in Dart 2.')
external static Future<Uri?> get packageRoot;
/// The location of the package configuration of the current isolate, if any.
///
/// If the isolate has not been setup for package resolution,
/// this location is `null`,
/// otherwise it is a URI referencing the package config file.
external static Future<Uri?> get packageConfig;
/// Maps a `package:` URI to a non-package Uri.
///
/// If there is no valid mapping from the `package:` URI in the current
/// isolate, then this call returns `null`. Non-`package:` URIs are
/// returned unmodified.
external static Future<Uri?> resolvePackageUri(Uri packageUri);
/// Creates and spawns an isolate that shares the same code as the current
/// isolate.
///
/// The argument [entryPoint] specifies the initial function to call
/// in the spawned isolate.
/// The entry-point function is invoked in the new isolate with [message]
/// as the only argument.
///
/// The function must be a top-level function or a static method
/// that can be called with a single argument,
/// that is, a compile-time constant function value
/// which accepts at least one positional parameter
/// and has at most one required positional parameter.
/// The function may accept any number of optional parameters,
/// as long as it *can* be called with just a single argument.
/// The function must not be the value of a function expression
/// or an instance method tear-off.
///
/// Usually the initial [message] contains a [SendPort] so
/// that the spawner and spawnee can communicate with each other.
///
/// If the [paused] parameter is set to `true`,
/// the isolate will start up in a paused state,
/// just before calling the [entryPoint] function with the [message],
/// as if by an initial call of `isolate.pause(isolate.pauseCapability)`.
/// To resume the isolate, call `isolate.resume(isolate.pauseCapability)`.
///
/// If the [errorsAreFatal], [onExit] and/or [onError] parameters are provided,
/// the isolate will act as if, respectively, [setErrorsFatal],
/// [addOnExitListener] and [addErrorListener] were called with the
/// corresponding parameter and was processed before the isolate starts
/// running.
///
/// If [debugName] is provided, the spawned [Isolate] will be identifiable by
/// this name in debuggers and logging.
///
/// If [errorsAreFatal] is omitted, the platform may choose a default behavior
/// or inherit the current isolate's behavior.
///
/// You can also call the [setErrorsFatal], [addOnExitListener] and
/// [addErrorListener] methods on the returned isolate, but unless the
/// isolate was started as [paused], it may already have terminated
/// before those methods can complete.
///
/// Returns a future which will complete with an [Isolate] instance if the
/// spawning succeeded. It will complete with an error otherwise.
external static Future<Isolate> spawn<T>(
void entryPoint(T message), T message,
{bool paused = false,
bool errorsAreFatal = true,
SendPort? onExit,
SendPort? onError,
@Since("2.3") String? debugName});
/// Creates and spawns an isolate that runs the code from the library with
/// the specified URI.
///
/// The isolate starts executing the top-level `main` function of the library
/// with the given URI.
///
/// The target `main` must be callable with zero, one or two arguments.
/// Examples:
///
/// * `main()`
/// * `main(args)`
/// * `main(args, message)`
///
/// When present, the parameter `args` is set to the provided [args] list.
/// When present, the parameter `message` is set to the initial [message].
///
/// If the [paused] parameter is set to `true`,
/// the isolate will start up in a paused state,
/// as if by an initial call of `isolate.pause(isolate.pauseCapability)`.
/// To resume the isolate, call `isolate.resume(isolate.pauseCapability)`.
///
/// If the [errorsAreFatal], [onExit] and/or [onError] parameters are provided,
/// the isolate will act as if, respectively, [setErrorsFatal],
/// [addOnExitListener] and [addErrorListener] were called with the
/// corresponding parameter and was processed before the isolate starts
/// running.
///
/// You can also call the [setErrorsFatal], [addOnExitListener] and
/// [addErrorListener] methods on the returned isolate, but unless the
/// isolate was started as [paused], it may already have terminated
/// before those methods can complete.
///
/// If the [checked] parameter is set to `true` or `false`,
/// the new isolate will run code in checked mode (enabling asserts and type
/// checks), respectively in production mode (disabling asserts and type
/// checks), if possible. If the parameter is omitted, the new isolate will
/// inherit the value from the current isolate.
///
/// In Dart2 strong mode, the `checked` parameter only controls asserts, but
/// not type checks.
///
/// It may not always be possible to honor the `checked` parameter.
/// If the isolate code was pre-compiled, it may not be possible to change
/// the checked mode setting dynamically.
/// In that case, the `checked` parameter is ignored.
///
/// WARNING: The [checked] parameter is not implemented on all platforms yet.
///
/// If the [packageConfig] parameter is provided, then it is used to find the
/// location of a package resolution configuration file for the spawned
/// isolate.
///
/// If the [automaticPackageResolution] parameter is provided, then the
/// location of the package sources in the spawned isolate is automatically
/// determined.
///
/// The [environment] is a mapping from strings to strings which the
/// spawned isolate uses when looking up [String.fromEnvironment] values.
/// The system may add its own entries to environment as well.
/// If `environment` is omitted, the spawned isolate has the same environment
/// declarations as the spawning isolate.
///
/// WARNING: The [environment] parameter is not implemented on all
/// platforms yet.
///
/// If [debugName] is provided, the spawned [Isolate] will be identifiable by
/// this name in debuggers and logging.
///
/// Returns a future that will complete with an [Isolate] instance if the
/// spawning succeeded. It will complete with an error otherwise.
external static Future<Isolate> spawnUri(
Uri uri,
List<String> args,
var message,
{bool paused = false,
SendPort? onExit,
SendPort? onError,
bool errorsAreFatal = true,
bool? checked,
Map<String, String>? environment,
@Deprecated('The packages/ dir is not supported in Dart 2')
Uri? packageRoot,
Uri? packageConfig,
bool automaticPackageResolution = false,
@Since("2.3")
String? debugName});
/// Requests the isolate to pause.
///
/// When the isolate receives the pause command, it stops
/// processing events from the event loop queue.
/// It may still add new events to the queue in response to, e.g., timers
/// or receive-port messages. When the isolate is resumed,
/// it starts handling the already enqueued events.
///
/// The pause request is sent through the isolate's command port,
/// which bypasses the receiving isolate's event loop.
/// The pause takes effect when it is received, pausing the event loop
/// as it is at that time.
///
/// The [resumeCapability] is used to identity the pause,
/// and must be used again to end the pause using [resume].
/// If [resumeCapability] is omitted, a new capability object is created
/// and used instead.
///
/// If an isolate is paused more than once using the same capability,
/// only one resume with that capability is needed to end the pause.
///
/// If an isolate is paused using more than one capability,
/// each pause must be individually ended before the isolate resumes.
///
/// Returns the capability that must be used to end the pause.
/// This is either [resumeCapability], or a new capability when
/// [resumeCapability] is omitted.
///
/// If [pauseCapability] is `null`, or it's not the pause capability
/// of the isolate identified by [controlPort],
/// the pause request is ignored by the receiving isolate.
Capability pause([Capability? resumeCapability]) {
resumeCapability ??= new Capability();
_pause(resumeCapability);
return resumeCapability;
}
/// Internal implementation of [pause].
external void _pause(Capability resumeCapability);
/// Resumes a paused isolate.
///
/// Sends a message to an isolate requesting that it ends a pause
/// that was previously requested.
///
/// When all active pause requests have been cancelled, the isolate
/// will continue processing events and handling normal messages.
///
/// If the [resumeCapability] is not one that has previously been used
/// to pause the isolate, or it has already been used to resume from
/// that pause, the resume call has no effect.
external void resume(Capability resumeCapability);
/// Requests an exit message on [responsePort] when the isolate terminates.
///
/// The isolate will send [response] as a message on [responsePort] as the last
/// thing before it terminates. It will run no further code after the message
/// has been sent.
///
/// Adding the same port more than once will only cause it to receive one exit
/// message, using the last response value that was added,
/// and it only needs to be removed once using [removeOnExitListener].
///
/// If the isolate has terminated before it can receive this request,
/// no exit message will be sent.
///
/// The [response] object must follow the same restrictions as enforced by
/// [SendPort.send].
/// It is recommended to only use simple values that can be sent to all
/// isolates, like `null`, booleans, numbers or strings.
///
/// Since isolates run concurrently, it's possible for it to exit before the
/// exit listener is established, and in that case no response will be
/// sent on [responsePort].
/// To avoid this, either use the corresponding parameter to the spawn
/// function, or start the isolate paused, add the listener and
/// then resume the isolate.
/* TODO(lrn): Can we do better? Can the system recognize this message and
* send a reply if the receiving isolate is dead?
*/
external void addOnExitListener(SendPort responsePort, {Object? response});
/// Stops listening for exit messages from the isolate.
///
/// Requests for the isolate to not send exit messages on [responsePort].
/// If the isolate isn't expecting to send exit messages on [responsePort],
/// because the port hasn't been added using [addOnExitListener],
/// or because it has already been removed, the request is ignored.
///
/// If the same port has been passed via [addOnExitListener] more than once,
/// only one call to `removeOnExitListener` is needed to stop it from receiving
/// exit messages.
///
/// Closing the receive port that is associated with the [responsePort] does
/// not stop the isolate from sending uncaught errors, they are just going to
/// be lost.
///
/// An exit message may still be sent if the isolate terminates
/// before this request is received and processed.
external void removeOnExitListener(SendPort responsePort);
/// Sets whether uncaught errors will terminate the isolate.
///
/// If errors are fatal, any uncaught error will terminate the isolate
/// event loop and shut down the isolate.
///
/// This call requires the [terminateCapability] for the isolate.
/// If the capability is absent or incorrect, no change is made.
///
/// Since isolates run concurrently, it's possible for the receiving isolate
/// to exit due to an error, before a request, using this method, has been
/// received and processed.
/// To avoid this, either use the corresponding parameter to the spawn
/// function, or start the isolate paused, set errors non-fatal and
/// then resume the isolate.
external void setErrorsFatal(bool errorsAreFatal);
/// Requests the isolate to shut down.
///
/// The isolate is requested to terminate itself.
/// The [priority] argument specifies when this must happen.
///
/// The [priority], when provided, must be one of [immediate] or
/// [beforeNextEvent] (the default).
/// The shutdown is performed at different times depending on the priority:
///
/// * `immediate`: The isolate shuts down as soon as possible.
/// Control messages are handled in order, so all previously sent control
/// events from this isolate will all have been processed.
/// The shutdown should happen no later than if sent with
/// `beforeNextEvent`.
/// It may happen earlier if the system has a way to shut down cleanly
/// at an earlier time, even during the execution of another event.
/// * `beforeNextEvent`: The shutdown is scheduled for the next time
/// control returns to the event loop of the receiving isolate,
/// after the current event, and any already scheduled control events,
/// are completed.
///
/// If [terminateCapability] is `null`, or it's not the terminate capability
/// of the isolate identified by [controlPort],
/// the kill request is ignored by the receiving isolate.
external void kill({int priority = beforeNextEvent});
/// Requests that the isolate send [response] on the [responsePort].
///
/// The [response] object must follow the same restrictions as enforced by
/// [SendPort.send].
/// It is recommended to only use simple values that can be sent to all
/// isolates, like `null`, booleans, numbers or strings.
///
/// If the isolate is alive, it will eventually send `response`
/// (defaulting to `null`) on the response port.
///
/// The [priority] must be one of [immediate] or [beforeNextEvent].
/// The response is sent at different times depending on the ping type:
///
/// * `immediate`: The isolate responds as soon as it receives the
/// control message. This is after any previous control message
/// from the same isolate has been received and processed,
/// but may be during execution of another event.
/// * `beforeNextEvent`: The response is scheduled for the next time
/// control returns to the event loop of the receiving isolate,
/// after the current event, and any already scheduled control events,
/// are completed.
external void ping(SendPort responsePort,
{Object? response, int priority = immediate});
/// Requests that uncaught errors of the isolate are sent back to [port].
///
/// The errors are sent back as two-element lists.
/// The first element is a `String` representation of the error, usually
/// created by calling `toString` on the error.
/// The second element is a `String` representation of an accompanying
/// stack trace, or `null` if no stack trace was provided.
/// To convert this back to a [StackTrace] object, use [StackTrace.fromString].
///
/// Listening using the same port more than once does nothing.
/// A port will only receive each error once,
/// and will only need to be removed once using [removeErrorListener].
///
/// Closing the receive port that is associated with the port does not stop
/// the isolate from sending uncaught errors, they are just going to be lost.
/// Instead use [removeErrorListener] to stop receiving errors on [port].
///
/// Since isolates run concurrently, it's possible for it to exit before the
/// error listener is established. To avoid this, start the isolate paused,
/// add the listener and then resume the isolate.
external void addErrorListener(SendPort port);
/// Stops listening for uncaught errors from the isolate.
///
/// Requests for the isolate to not send uncaught errors on [port].
/// If the isolate isn't expecting to send uncaught errors on [port],
/// because the port hasn't been added using [addErrorListener],
/// or because it has already been removed, the request is ignored.
///
/// If the same port has been passed via [addErrorListener] more than once,
/// only one call to `removeErrorListener` is needed to stop it from receiving
/// uncaught errors.
///
/// Uncaught errors message may still be sent by the isolate
/// until this request is received and processed.
external void removeErrorListener(SendPort port);
/// Returns a broadcast stream of uncaught errors from the isolate.
///
/// Each error is provided as an error event on the stream.
///
/// The actual error object and stackTraces will not necessarily
/// be the same object types as in the actual isolate, but they will
/// always have the same [Object.toString] result.
///
/// This stream is based on [addErrorListener] and [removeErrorListener].
Stream get errors {
StreamController controller = StreamController.broadcast(sync: true);
RawReceivePort? port;
void handleError(Object? message) {
var listMessage = message as List<Object?>;
var errorDescription = listMessage[0] as String;
var stackDescription = listMessage[1] as String;
var error = new RemoteError(errorDescription, stackDescription);
controller.addError(error, error.stackTrace);
}
controller.onListen = () {
RawReceivePort receivePort = new RawReceivePort(handleError);
port = receivePort;
this.addErrorListener(receivePort.sendPort);
};
controller.onCancel = () {
var listenPort = port!;
port = null;
this.removeErrorListener(listenPort.sendPort);
listenPort.close();
};
return controller.stream;
}
/// Terminates the current isolate synchronously.
///
/// This operations is potentially dangerous and should be used judiciously.
/// The isolate stops operating *immediately*. It throws if optional [message]
/// does not adhere to the limitation on what can be send from one isolate to
/// another. It also throws if a [finalMessagePort] is associated with an
/// isolate spawned outside of current isolate group, spawned via [spawnUri].
///
/// If successful, a call to this method does not return. Pending `finally`
/// blocks are not executed, control flow will not go back to the event loop,
/// scheduled asynchronous asks will never run, and even pending isolate
/// control commands may be ignored. (The isolate will send messages to ports
/// already registered using [Isolate.addOnExitListener], but no further Dart
/// code will run in the isolate.)
///
/// If [finalMessagePort] is provided, and the [message] can be sent through
/// it, then the message is sent through that port as the final operation of
/// the current isolate. The isolate terminates immediately after
/// that [SendPort.send] call returns.
///
/// (If the port is a native port, one provided by [ReceivePort.sendPort]
/// or [RawReceivePort.sendPort], the system may be able to send this final
/// message more efficiently than normal port communication between live
/// isolates.)
external static Never exit([SendPort? finalMessagePort, Object? message]);
}
/// Sends messages to its [ReceivePort]s.
///
/// [SendPort]s are created from [ReceivePort]s. Any message sent through
/// a [SendPort] is delivered to its corresponding [ReceivePort]. There might be
/// many [SendPort]s for the same [ReceivePort].
///
/// [SendPort]s can be transmitted to other isolates, and they preserve equality
/// when sent.
abstract class SendPort implements Capability {
/// Sends an asynchronous [message] through this send port, to its
/// corresponding `ReceivePort`.
///
/// The content of [message] can be:
/// - [Null]
/// - [bool]
/// - [int]
/// - [double]
/// - [String]
/// - [List] or [Map] (whose elements are any of these)
/// - [TransferableTypedData]
/// - [SendPort]
/// - [Capability]
///
/// In the special circumstances when two isolates share the same code and are
/// running in the same process (e.g. isolates created via [Isolate.spawn]),
/// it is also possible to send object instances (which would be copied in the
/// process). This is currently only supported by the
/// [Dart Native](https://dart.dev/platforms#dart-native-vm-jit-and-aot)
/// platform.
///
/// The send happens immediately and doesn't block. The corresponding receive
/// port can receive the message as soon as its isolate's event loop is ready
/// to deliver it, independently of what the sending isolate is doing.
void send(Object? message);
/// Tests whether [other] is a [SendPort] pointing to the same
/// [ReceivePort] as this one.
bool operator ==(var other);
/// A hash code for this send port that is consistent with the == operator.
int get hashCode;
}
/// Together with [SendPort], the only means of communication between isolates.
///
/// [ReceivePort]s have a `sendPort` getter which returns a [SendPort].
/// Any message that is sent through this [SendPort]
/// is delivered to the [ReceivePort] it has been created from. There, the
/// message is dispatched to the `ReceivePort`'s listener.
///
/// A [ReceivePort] is a non-broadcast stream. This means that it buffers
/// incoming messages until a listener is registered. Only one listener can
/// receive messages. See [Stream.asBroadcastStream] for transforming the port
/// to a broadcast stream.
///
/// A [ReceivePort] may have many [SendPort]s.
abstract class ReceivePort implements Stream<dynamic> {
/// Opens a long-lived port for receiving messages.
///
/// A [ReceivePort] is a non-broadcast stream. This means that it buffers
/// incoming messages until a listener is registered. Only one listener can
/// receive messages. See [Stream.asBroadcastStream] for transforming the port
/// to a broadcast stream.
///
/// The optional `debugName` parameter can be set to associate a name with
/// this port that can be displayed in tooling.
///
/// A receive port is closed by canceling its subscription.
external factory ReceivePort([String debugName = '']);
/// Creates a [ReceivePort] from a [RawReceivePort].
///
/// The handler of the given [rawPort] is overwritten during the construction
/// of the result.
external factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort);
/// Listen for events from [Stream].
///
/// See [Stream.listen].
///
/// Note that [onError] and [cancelOnError] are ignored since a [ReceivePort]
/// will never receive an error.
///
/// The [onDone] handler will be called when the stream closes.
/// The stream closes when [close] is called.
StreamSubscription<dynamic> listen(void onData(var message)?,
{Function? onError, void onDone()?, bool? cancelOnError});
/// Closes the receive port.
///
/// No further events will be received by the receive port,
/// or emitted as stream events.
///
/// If [listen] has been called and the [StreamSubscription] has not
/// been canceled yet, the subscription will be closed with a "done"
/// event.
///
/// If the stream has already been canceled this method has no effect.
void close();
/// A [SendPort] which sends messages to this receive port.
SendPort get sendPort;
}
/// A low-level asynchronous message receiver.
///
/// A [RawReceivePort] is low level feature, and is not [Zone] aware.
/// The [handler] will always be invoked in the [Zone.root] zone.
///
/// The port cannot be paused. The data-handler must be set before the first
/// message is received, otherwise the message is lost.
///
/// Messages can be sent to this port using [sendPort].
abstract class RawReceivePort {
/// Opens a long-lived port for receiving messages.
///
/// A [RawReceivePort] is low level and does not work with [Zone]s. It
/// cannot be paused. The data-handler must be set before the first
/// message is received, otherwise the message is lost.
///
/// If [handler] is provided, it's set as the [RawReceivePort.handler].
///
/// The optional `debugName` parameter can be set to associate a name with
/// this port that can be displayed in tooling.
external factory RawReceivePort([Function? handler, String debugName = '']);
/// Sets the handler that is invoked for every incoming message.
///
/// The handler is invoked in the [Zone.root] zone.
/// If the handler should be invoked in the current zone, do:
/// ```dart
/// rawPort.handler = Zone.current.bind(actualHandler);
/// ```
///
/// The handler must be a function which can accept one argument
/// of the type of the messages sent to this port.
/// This means that if it is known that messages will all be [String]s,
/// a handler of type `void Function(String)` can be used.
/// The function is invoked dynamically with the actual messages,
/// and if this invocation fails,
/// the error becomes a top-level uncaught error in the [Zone.root] zone.
// TODO(44659): Change parameter type to `void Function(Never)` to only
// accept functions which can be called with one argument.
void set handler(Function? newHandler);
/// Closes the port.
///
/// After a call to this method, any incoming message is silently dropped.
/// The [handler] will never be called again.
void close();
/// Returns a [SendPort] that sends messages to this raw receive port.
SendPort get sendPort;
}
/// Description of an error from another isolate.
///
/// This error has the same `toString()` and `stackTrace.toString()` behavior
/// as the original error, but has no other features of the original error.
class RemoteError implements Error {
final String _description;
final StackTrace stackTrace;
RemoteError(String description, String stackDescription)
: _description = description,
stackTrace = new StackTrace.fromString(stackDescription);
String toString() => _description;
}
/// An efficiently transferable sequence of byte values.
///
/// A [TransferableTypedData] is created from a number of bytes.
/// This will take time proportional to the number of bytes.
///
/// The [TransferableTypedData] can be moved between isolates, so
/// sending it through a send port will only take constant time.
///
/// When sent this way, the local transferable can no longer be materialized,
/// and the received object is now the only way to materialize the data.
@Since("2.3.2")
abstract class TransferableTypedData {
/// Creates a new [TransferableTypedData] containing the bytes of [list].
///
/// It must be possible to create a single [Uint8List] containing the
/// bytes, so if there are more bytes than what the platform allows in
/// a single [Uint8List], then creation fails.
external factory TransferableTypedData.fromList(List<TypedData> list);
/// Creates a new [ByteBuffer] containing the bytes stored in this [TransferableTypedData].
///
/// The [TransferableTypedData] is a cross-isolate single-use resource.
/// This method must not be called more than once on the same underlying
/// transferable bytes, even if the calls occur in different isolates.
ByteBuffer materialize();
}