Exemplo n.º 1
0
        public static IDisposable ObtainSinkInactiveState(this ITimeSink @this)
        {
            var result = new DisposableWrapper();

            @this.TimeHandle.SinkSideActive = false;
            result.RegisterDisposeAction(() => @this.TimeHandle.SinkSideActive = true);
            return(result);
        }
 /// <see cref="ITimeSource.RegisterSink">
 public void RegisterSink(ITimeSink sink)
 {
     //lock(handles)
     using (sync.HighPriority)
     {
         handles.Add(new TimeHandle(this, sink)
         {
             SourceSideActive = isStarted
         });
     }
 }
Exemplo n.º 3
0
        // -------
        // The objects of this class are used to synchronize execution of `time sources` and `time sinks`.
        //
        // [SOURCE SIDE]                                   [SINK SIDE]
        //                                   Dispose
        //                                      |
        //                                      V
        //                                 +--------+
        // Latch                       ->  |        |
        // ...                             |        |
        // (Grant + (Latch))           ->  |        |  <-  Request* + (Unblock + Latch)
        // ...                             |  Time  |      ...
        // WaitUntilDone* + (Unlatch)  ->  | Handle |  <-  ReportBreak / ReportContinue
        // ...                             |        |
        // Unlatch                     ->  |        |
        //                                 |        |
        //                                 +--------+
        //                             --- properties ---
        //                                 +--------+
        // SourceSideActive            =   |        |  =   SinkSideActive
        //                                 |        |  =   Enabled
        //                                 +--------+
        //
        //
        // Methods marked with '*' are blocking:
        // * `Request` will block until `Grant`
        // * `WaitUntilDone` will block until `ReportBreak` or `ReportContinue`
        //
        // Methods surrounded with '()' are executed conditionally:
        // * `Latch` as a result of `Request` is executed only if this is the first `Request` after `ReportBreak`
        // * `Unlatch` as a result of `WaitUntilDone` is executed only if this is the first `WaitUntilDone` after successful unblocking of the handle
        // * `Grant` is not executed as long as the previous `WaitUntilDone` does not finish successfully, returning `true`
        //
        //
        // SOURCE SIDE simplified algorithm:
        // (1)  `Latch` the handle
        // (2?) `Grant` time or skip the step if previous `WaitUntilDone` failed
        // (3)  Call `WaitUntilDone`
        // (4)  `Unlatch` the handle
        // (5)  Go to p. (1)
        //
        // SINK SIDE simplified algorithm:
        // (1) 'Request' time
        // (2) Execute the time-aware code for a given virtual time
        //   (2.1) Finish the execution when granted virtual time is depleted using `ReportContinue`
        //   (2.2) Stop the execution in an arbitrary moment with the intent of resuming in the future and use `ReportBreak`
        // (3) Go to p. (1)
        //
        //
        // Properties:
        // * `SourceSideActive` - when set to `false`: `Request` returns immediately with the `false` result
        // * `SinkSideActive`   - when set to `false`: `WaitUntilDone` returns immediately with the `false` result
        // * `Enabled`          - when set to `false`: `WaitUntilDone` returns immediately with the `true` result
        //
        // Internal state:
        // * `sourceSideInProgress` - `true` from  `Grant`                            to  `WaitUntilDone` or `Dispose`
        // * `sinkSideInProgress`   - `true` from  `Request`                          to  `ReportBreak` or `ReportContinue` or `Dispose`
        // * `grantPending`         - `true` from  `Grant`                            to  `Request`
        // * `reportPending`        - `true` from  `ReportBreak` or `ReportContinue`  to  `WaitUntilDone`
        // * `isBlocking`           - `true` from  `ReportBreak`                      to  `Request`
        //
        // Additional notes:
        //
        // 1. `Active` means that the code on source/sink side is working and follows the above-mentioned algorithm.
        // Going `inactive` is a signal for a handle that its operations should not block anymore as there is no chance for their successful termination in the nearest future (i.e., as long as the handle is inactive).
        //
        // 2. When the handle is `disabled`, it does not inform the sink about passed time but immediately reports back, thus not blocking execution of other handles.
        //
        // 3. The handle is not allowed to resume the execution after reporting a break, without the explicit permission obtained from the time source.
        // This is why `Request` calls and waits for the result of `UnblockHandle` when executed in a blocking state.
        // Once the permission is granted, the handle uses what is left from the previous quantum instead of waiting for a new one.
        //
        // 4. Latching is needed to ensure that the handle will not become disabled/re-enabled in an arbitrary moment.
        // As described in (2), the disabled handle does not synchronize the sink side, so it cannot switch state when the sink is in progress of an execution and the sink cannot resume execution when the source side is in progress.
        // -------

        /// <summary>
        /// Creates a new time handle and associates it with <paramref name="timeSource"/>.
        /// </summary>
        public TimeHandle(ITimeSource timeSource, ITimeSink timeSink)
        {
            innerLock = new object();
            enabled   = true;

            TimeSource       = timeSource;
            TotalElapsedTime = timeSource.ElapsedVirtualTime;

            // we should not assign this handle to TimeSink as the source might not be configured properly yet
            TimeSink = timeSink;

            this.Trace();
        }
Exemplo n.º 4
0
        // -------
        // The objects of this class are used to synchronize execution of `time sources` and `time sinks`.
        //
        // [SOURCE SIDE]                                   [SINK SIDE]
        //                                   Dispose
        //                                      |
        //                                      V
        //                                 +--------+
        // Latch                       ->  |        |
        // ...                             |        |
        // (Grant + (Latch))           ->  |        |  <-  Request* + (Unblock + Latch)
        // ...                             |  Time  |      ...
        // WaitUntilDone* + (Unlatch)  ->  | Handle |  <-  ReportBreak / ReportContinue
        // ...                             |        |
        // Unlatch                     ->  |        |
        //                                 |        |
        //                                 +--------+
        //                             --- properties ---
        //                                 +--------+
        // SourceSideActive            =   |        |  =   SinkSideActive
        //                                 |        |  =   Enabled
        //                                 +--------+
        //
        //
        // Methods marked with '*' are blocking:
        // * `Request` will block until `Grant`
        // * `WaitUntilDone` will block until `ReportBreak` or `ReportContinue`
        //
        // Methods surrounded with '()' are executed conditionally:
        // * `Latch` as a result of `Request` is executed only if this is the first `Request` after `ReportBreak`
        // * `Unlatch` as a result of `WaitUntilDone` is executed only if this is the first `WaitUntilDone` after successful unblocking of the handle
        // * `Grant` is not executed as long as the previous `WaitUntilDone` does not finish successfully, returning `true`
        //
        //
        // SOURCE SIDE simplified algorithm:
        // (1)  `Latch` the handle
        // (2?) `Grant` time or skip the step if previous `WaitUntilDone` failed
        // (3)  Call `WaitUntilDone`
        // (4)  `Unlatch` the handle
        // (5)  Go to p. (1)
        //
        // SINK SIDE simplified algorithm:
        // (1) 'Request' time
        // (2) Execute the time-aware code for a given virtual time
        //   (2.1) Finish the execution when granted virtual time is depleted using `ReportContinue`
        //   (2.2) Stop the execution in an arbitrary moment with the intent of resuming in the future and use `ReportBreak`
        // (3) Go to p. (1)
        //
        //
        // Properties:
        // * `SourceSideActive` - when set to `false`: `Request` returns immediately with the `false` result
        // * `SinkSideActive`   - when set to `false`: `WaitUntilDone` returns immediately with the `false` result
        // * `Enabled`          - when set to `false`: `WaitUntilDone` returns immediately with the `true` result
        //
        // Internal state:
        // * `sourceSideInProgress` - `true` from  `Grant`                            to  `WaitUntilDone` or `Dispose`
        // * `sinkSideInProgress`   - `true` from  `Request`                          to  `ReportBreak` or `ReportContinue` or `Dispose`
        // * `grantPending`         - `true` from  `Grant`                            to  `Request`
        // * `reportPending`        - `true` from  `ReportBreak` or `ReportContinue`  to  `WaitUntilDone`
        // * `isBlocking`           - `true` from  `ReportBreak`                      to  `Request`
        //
        // Additional notes:
        //
        // 1. `Active` means that the code on source/sink side is working and follows the above-mentioned algorithm.
        // Going `inactive` is a signal for a handle that its operations should not block anymore as there is no chance for their successful termination in the nearest future (i.e., as long as the handle is inactive).
        //
        // 2. When the handle is `disabled`, it does not inform the sink about passed time but immediately reports back, thus not blocking execution of other handles.
        //
        // 3. The handle is not allowed to resume the execution after reporting a break, without the explicit permission obtained from the time source.
        // This is why `Request` calls and waits for the result of `UnblockHandle` when executed in a blocking state.
        // Once the permission is granted, the handle uses what is left from the previous quantum instead of waiting for a new one.
        //
        // 4. Latching is needed to ensure that the handle will not become disabled/re-enabled in an arbitrary moment.
        // As described in (2), the disabled handle does not synchronize the sink side, so it cannot switch state when the sink is in progress of an execution and the sink cannot resume execution when the source side is in progress.
        // -------

        /// <summary>
        /// Creates a new time handle and associates it with <paramref name="timeSource"/>.
        /// </summary>
        public TimeHandle(ITimeSource timeSource, ITimeSink timeSink)
        {
            innerLock = new object();
            enabled   = true;

            TimeSource       = timeSource;
            TotalElapsedTime = timeSource.ElapsedVirtualTime;

            TimeSink            = timeSink;
            TimeSink.TimeHandle = this;

            this.Trace();
        }
Exemplo n.º 5
0
        // -------
        // The objects of this class are used to synchronize execution of `time sources` and `time sinks`.
        //
        // [SOURCE SIDE]                                   [SINK SIDE]
        //                                   Dispose
        //                                      |
        //                                      V
        //                                 +--------+
        // Latch                       ->  |        |
        // ...                             |        |
        // (Grant / Unblock + (Latch)) ->  |        |  <-  Request* + (Latch)
        // ...                             |  Time  |      ...
        // WaitUntilDone* + (Unlatch)  ->  | Handle |  <-  ReportBreak / ReportContinue
        // ...                             |        |
        // Unlatch                     ->  |        |
        //                                 |        |
        //                                 +--------+
        //                             --- properties ---
        //                                 +--------+
        // SourceSideActive            =   |        |  =   SinkSideActive
        //                                 |        |  =   Enabled
        //                                 +--------+
        //
        //
        // Methods marked with '*' are blocking:
        // * `Request` will block until `Grant` or `Unblock`
        // * `WaitUntilDone` will block until `ReportBreak` or `ReportContinue`
        //
        // Methods surrounded with '()' are executed conditionally:
        // * `Latch` as a result of `Request` is executed only if this is the first `Request` after `ReportBreak`
        // * `Unlatch` as a result of `WaitUntilDone` is executed only if this is the first `WaitUntilDone` after successful unblocking of the handle
        // * `Grant` is not executed as long as the previous `WaitUntilDone` does not finish successfully, returning `true`
        // * `Unlock` is executed only when the previous `WaitUntilDone` returned `false`
        //
        //
        // SOURCE SIDE simplified algorithm:
        // (1)  `Latch` the handle
        // (2?) `Grant` time or `Unblock` the handle if previous `WaitUntilDone` failed
        // (3)  Call `WaitUntilDone`
        // (4)  `Unlatch` the handle
        // (5)  Go to p. (1)
        //
        // SINK SIDE simplified algorithm:
        // (1) 'Request' time
        // (2) Execute the time-aware code for a given virtual time
        //   (2.1) Finish the execution when granted virtual time is depleted using `ReportContinue`
        //   (2.2) Stop the execution in an arbitrary moment with the intent of resuming in the future and use `ReportBreak`
        // (3) Go to p. (1)
        //
        //
        // Properties:
        // * `SourceSideActive` - when set to `false`: `Request` returns immediately with the `false` result
        // * `SinkSideActive`   - when set to `false`: `WaitUntilDone` returns immediately with the `false` result
        // * `Enabled`          - when set to `false`: `WaitUntilDone` returns immediately with the `true` result
        // * `DeferredEnabled`  - `Enabled` will be assigned this value when unlatched
        //
        // Internal state:
        // * `sourceSideInProgress` - `true` from  `Grant`                            to  `WaitUntilDone` or `Dispose`
        // * `sinkSideInProgress`   - `true` from  `Request`                          to  `ReportBreak` or `ReportContinue` or `Dispose`
        // * `grantPending`         - `true` from  `Grant` or `Unblock`               to  `Request`
        // * `reportPending`        - `true` from  `ReportBreak` or `ReportContinue`  to  `WaitUntilDone`
        // * `isBlocking`           - `true` from  `ReportBreak`                      to  `Request`
        //
        // Additional notes:
        //
        // 1. `Active` means that the code on source/sink side is working and follows the above-mentioned algorithm.
        // Going `inactive` is a signal for a handle that its operations should not block anymore as there is no chance for their successful termination in the nearest future (i.e., as long as the handle is inactive).
        //
        // 2. When the handle is `disabled`, it does not inform the sink about passed time but immediately reports back, thus not blocking execution of other handles.
        //
        // 3. The handle is not allowed to resume the execution after reporting a break, without the explicit permission obtained from the time source.
        // This is why the call of `Request` waits for the `UnblockHandle` when executed in a blocking state.
        // Once the permission is granted, the handle uses what is left from the previous quantum instead of waiting for a new one.
        //
        // 4. Latching is needed to ensure that the handle will not become disabled/re-enabled in an arbitrary moment.
        // As described in (2), the disabled handle does not synchronize the sink side, so it cannot switch state when the sink is in progress of an execution and the sink cannot resume execution when the source side is in progress.
        // It is possible to defer changing value of `Enabled` by using `DeferredEnabled` property - their values will be automatically synced (i.e., `Enabled` will get `DeferredEnabled` value) when unlatching the handle.
        // -------

        /// <summary>
        /// Creates a new time handle and associates it with <paramref name="timeSource"/>.
        /// </summary>
        public TimeHandle(ITimeSource timeSource, ITimeSink timeSink)
        {
            innerLock       = new object();
            enabled         = true;
            DeferredEnabled = true;

            TimeSource = timeSource;

            // we should not assign this handle to TimeSink as the source might not be configured properly yet
            TimeSink = timeSink;

            Reset();
            this.Trace();
        }
Exemplo n.º 6
0
        /// <see cref="ITimeSource.RegisterSink">
        public void RegisterSink(ITimeSink sink)
        {
            using (sync.HighPriority)
            {
                var handle = new TimeHandle(this, sink)
                {
                    SourceSideActive = isStarted
                };
                StopRequested += handle.RequestPause;
                handles.Add(handle);
#if DEBUG
                this.Trace($"Registering sink ({(sink as IIdentifiable)?.GetDescription()}) in source ({this.GetDescription()}) via handle ({handle.GetDescription()})");
#endif
                // assigning TimeHandle to a sink must be done when everything is configured, otherwise a race condition might happen (dispatcher starts its execution when time source and handle are not yet ready)
                sink.TimeHandle = handle;
            }
        }
Exemplo n.º 7
0
 public void RegisterSink(ITimeSink sink)
 {
     throw new NotImplementedException();
 }