@@ -54,7 +54,7 @@ abstract class IsoSystem {
54
54
* @param scheduler the scheduler used to scheduler the isolate
55
55
* @return the channel for this isolate
56
56
*/
57
- def isolate [@ spec(Int , Long , Double ) T : Arrayable ](proto : Proto [Iso [T ]], name : String = null ): Channel [T ]
57
+ def isolate [@ spec(Int , Long , Double ) T : Arrayable ](proto : Proto [Iso [T ]]): Channel [T ]
58
58
59
59
/** Creates a new channel for the specified isolate frame.
60
60
*
@@ -77,11 +77,14 @@ abstract class IsoSystem {
77
77
*/
78
78
protected def uniqueName (name : String ): String
79
79
80
- /** Releases the name after the isolate terminates.
80
+ /** Releases the channel names associated with the isolate,
81
+ * and then releases the name of the isolate.
82
+ *
83
+ * Called after the isolate terminates.
81
84
*
82
85
* @param name the name to release
83
86
*/
84
- protected [reactive] def releaseName (name : String ): Unit
87
+ protected [reactive] def releaseNames (name : String ): Unit
85
88
86
89
/** Generates a new unique id, generated only once during
87
90
* the lifetime of this isolate system.
@@ -107,14 +110,18 @@ abstract class IsoSystem {
107
110
/** Creates an isolate frame.
108
111
*
109
112
* Should only be overridden if the default isolate initialization order needs to change.
113
+ * The multiplexer, unique name and unique id are created for an isolate first.
114
+ * Then, the isolate frame is created.
115
+ * Then, the isolate object (concrete user implementation) is instantiated.
116
+ * Then, the isolate frame is assigned the isolate object.
117
+ * Finally, the `initiate` method is called on the scheduler, and the isolate is returned.
110
118
* See the source code of the default implementation of this method for more details.
111
119
*
112
120
* @tparam T the type of the events for the isolate
113
121
* @param proto prototype for the isolate
114
- * @param name name of the new isolate
115
122
* @return the resulting isolate frame
116
123
*/
117
- protected def createFrame [@ spec(Int , Long , Double ) T : Arrayable ](proto : Proto [Iso [T ]], name : String ): Iso [T ] = {
124
+ protected def createFrame [@ spec(Int , Long , Double ) T : Arrayable ](proto : Proto [Iso [T ]]): Iso [T ] = {
118
125
val scheduler = proto.scheduler match {
119
126
case null => bundle.defaultScheduler
120
127
case name => bundle.scheduler(name)
@@ -128,16 +135,16 @@ abstract class IsoSystem {
128
135
case mult => mult
129
136
}
130
137
val uid = uniqueId()
131
- val uname = uniqueName(name)
138
+ val uname = uniqueName(proto. name)
132
139
val frame = new IsoFrame (
133
140
uid,
134
141
uname,
135
142
IsoSystem .this ,
136
143
scheduler,
137
144
queueFactory,
138
145
multiplexer,
139
- frame => Iso .openChannel(frame, queueFactory, false ),
140
- frame => Iso .openChannel(frame, queueFactory, true )
146
+ frame => IsoSystem .openChannel(IsoSystem . this , frame, queueFactory, " events " , false ),
147
+ frame => IsoSystem .openChannel(IsoSystem . this , frame, queueFactory, " internal " , true )
141
148
)
142
149
val isolate = Iso .argFrame.withValue(frame) {
143
150
createAndResetIso(proto)
@@ -154,6 +161,19 @@ abstract class IsoSystem {
154
161
*/
155
162
object IsoSystem {
156
163
164
+ /** Opens a channel for the current isolate, using the specified parameters.
165
+ */
166
+ private [reactive] def openChannel [@ spec(Int , Long , Double ) Q : Arrayable ](system : IsoSystem , frame : IsoFrame , f : EventQueue .Factory , cn : String , isDaemon : Boolean ): Connector [Q ] = {
167
+ val factory = if (f != null ) f else Iso .self.frame.eventQueueFactory
168
+ val channelName = if (cn != null ) cn else " channel-" + frame.counter.incrementAndGet().toString
169
+ val eventQueue = factory.create[Q ]
170
+ val name = frame.name + " #" + channelName
171
+ val connector = new Connector (frame, eventQueue, name, isDaemon)
172
+ system.channels(name) = connector.channel
173
+ frame.multiplexer += connector
174
+ connector
175
+ }
176
+
157
177
/** Retrieves the default isolate system.
158
178
*
159
179
* @param name the name for the isolate system instance
@@ -210,41 +230,58 @@ object IsoSystem {
210
230
*/
211
231
lazy val defaultBundle = Bundle .default(Scheduler .default)
212
232
233
+ class ChannelBuilder (
234
+ val system : IsoSystem ,
235
+ val channelName : String ,
236
+ val isDaemon : Boolean ,
237
+ val eventQueueFactory : EventQueue .Factory
238
+ ) {
239
+ /** Associates a new name for the channel.
240
+ */
241
+ def named (name : String ) = new ChannelBuilder (system, name, isDaemon, eventQueueFactory)
242
+
243
+ /** Specifies a daemon channel.
244
+ */
245
+ def daemon = new ChannelBuilder (system, channelName, true , eventQueueFactory)
246
+
247
+ /** Associates a new event queue factory.
248
+ */
249
+ def eventQueue (factory : EventQueue .Factory ) = new ChannelBuilder (system, channelName, isDaemon, factory)
250
+
251
+ /** Opens a new channel for this isolate.
252
+ *
253
+ * @tparam Q type of the events in the new channel
254
+ * @param factory event queue factory
255
+ * @return the connector object of the new channel
256
+ */
257
+ final def open [@ spec(Int , Long , Double ) Q : Arrayable ]: Connector [Q ] =
258
+ IsoSystem .openChannel[Q ](system, Iso .self.frame, eventQueueFactory, channelName, isDaemon)
259
+ }
260
+
213
261
/** The channel register used for channel lookup by name.
214
262
*/
215
- trait Channels {
263
+ abstract class Channels (system : IsoSystem ) extends ChannelBuilder (system, null , false , null ) {
264
+
216
265
/** Registers a new channel with this isolate system.
217
266
*
218
267
* Throws an exception if name is already taken.
219
268
*
220
269
* @param name name of the channel
221
270
* @param channel the channel to register
222
271
*/
223
- def update (name : String , channel : Channel [_]): Unit
272
+ private [reactive] def update (name : String , channel : Channel [_]): Unit
224
273
225
274
/** Removes the channel registration.
226
275
*
227
276
* @param name name of the channel to remove from the register
228
277
*/
229
- def remove (name : String ): Unit
230
-
231
- /** Returns a channel under the specified name, if any.
232
- *
233
- * Throws an exception if such a channel does not exist.
234
- *
235
- * @param name name of the channel
236
- * @return the channel registered under the specified name
237
- */
238
- def apply [@ spec(Int , Long , Double ) T ](name : String ): Channel [T ]
278
+ private [reactive] def remove (name : String ): Unit
239
279
240
- /** Returns a channel under the specified name, if any .
280
+ /** Removes all the channels registered with a specific isolate .
241
281
*
242
- * Returns `None` if none exist.
243
- *
244
- * @param name name of the channel
245
- * @return optionally, the channel registered under the specified name
282
+ * @param isoName name of the isolate whose channels must be removed
246
283
*/
247
- def get [ T ]( name : String ): Option [ Channel [ T ]]
284
+ private [reactive] def removeIsolate ( isoName : String ): Unit
248
285
249
286
/** Eventually returns a channel under the specified name.
250
287
*
@@ -255,6 +292,9 @@ object IsoSystem {
255
292
256
293
/** Eventually returns an *unsealed* channel under the specified name.
257
294
*
295
+ * Note: between the time that the channel is retrieved and the time it is first used,
296
+ * that channel can asynchronously become sealed.
297
+ *
258
298
* @param name name of the channel
259
299
* @return the ivar with the channel registered under the specified name
260
300
*/
@@ -265,20 +305,19 @@ object IsoSystem {
265
305
266
306
/** A default implementation of the channels register.
267
307
*/
268
- class Default extends IsoSystem .Channels {
308
+ class Default ( system : IsoSystem ) extends IsoSystem .Channels (system) {
269
309
private val channelMap = container.RMap [String , Channel [_]]
270
- def update (name : String , c : Channel [_]) = channelMap.synchronized {
310
+ private [reactive] def update (name : String , c : Channel [_]) = channelMap.synchronized {
271
311
if (! channelMap.contains(name)) channelMap(name) = c
272
312
else sys.error(s " Name $name already contained in channels. " )
273
313
}
274
- def apply [@ spec(Int , Long , Double ) T ](name : String ): Channel [T ] = channelMap.synchronized {
275
- channelMap(name).asInstanceOf [Channel [T ]]
276
- }
277
- def remove (name : String ): Unit = channelMap.synchronized {
314
+ private [reactive] def remove (name : String ): Unit = channelMap.synchronized {
278
315
channelMap.remove(name)
279
316
}
280
- def get [T ](name : String ): Option [Channel [T ]] = channelMap.synchronized {
281
- channelMap.get(name).asInstanceOf [Option [Channel [T ]]]
317
+ private [reactive] def removeIsolate (isoName : String ): Unit = channelMap.synchronized {
318
+ val prefix = isoName + " #"
319
+ val obsoleteNames = channelMap.keys.filter(_ startsWith prefix)
320
+ for (name <- obsoleteNames) channelMap.remove(name)
282
321
}
283
322
private def channelExtractor [T ](reqId : Long ): PartialFunction [InternalEvent , Channel [T ]] = {
284
323
case ChannelRetrieved (`reqId`, c : Channel [T ]) => c
0 commit comments