Skip to content
Start free evaluation

PDComm.GemWorker

Class

Provides the members shared by GemHostWorker and GemEquipmentWorker: a GEM endpoint owned by a dedicated polling thread.

public abstract class GemWorker : IAsyncDisposable

The worker thread creates, starts and owns the endpoint. It polls the transport, passes every transport event to GemEndpoint.HandleEvent, and buffers the resulting GemEvent objects for GemWorker.ReadEventsAsync. Between polls it waits up to HsmsWorkerOptions.PollIntervalMilliseconds unless new work arrives.

Each *Async command is queued and runs on the worker thread in submission order. The queue accepts at most HsmsWorkerOptions.CommandCapacity commands and HsmsWorkerOptions.MaxCommandBytes of command input; a command beyond either limit is not queued and its task faults with PdcommException (PdcommStatus.Backpressure). Input buffers are copied before a command method returns.

The event buffer holds at most HsmsWorkerOptions.EventCapacity events and HsmsWorkerOptions.MaxEventBytes; each event reserves its raw body length plus the GEM item limit SecsLimits.MessageBytes for its result. While the buffer is full, the worker stops reading and polling the transport, and commands that send messages fail with PdcommStatus.Backpressure, so keep reading events.

Stop the worker with GemWorker.StopAsync and wait for GemWorker.Completion, then release it with GemWorker.DisposeAsync, typically through await using.

Members

BeginCommunicationAsync

Method

Queues GemEndpoint.BeginCommunication on the worker thread to send S1F13.

public Task<HsmsToken> BeginCommunicationAsync(CancellationToken cancellationToken = default)

The command runs on the worker thread, which owns the endpoint. The task faults with PdcommException (PdcommStatus.Backpressure) when the command queue or its byte budget is full or when the command runs while event output is blocked because the event buffer is full, faults with ObjectDisposedException after the worker stopped accepting commands, and is canceled when cancellationToken is canceled before the command runs. Otherwise it carries any exception of GemEndpoint.BeginCommunication.

Parameters

NameDescription
cancellationTokenA token that cancels the command if it has not run yet.

Returns

A task that completes with the token of the S1F13 request once it is sent; the S1F14 reply arrives as a GemEvent.

CancelAsync

Method

Queues GemEndpoint.Cancel on the worker thread.

public Task<bool> CancelAsync(HsmsToken token, CancellationToken cancellationToken = default)

The command runs on the worker thread, which owns the endpoint. The task faults with PdcommException (PdcommStatus.Backpressure) when the command queue or its byte budget is full, faults with ObjectDisposedException after the worker stopped accepting commands, and is canceled when cancellationToken is canceled before the command runs. Otherwise it carries any exception of GemEndpoint.Cancel.

Parameters

NameDescription
tokenThe token returned when the request was submitted.
cancellationTokenA token that cancels the command if it has not run yet.

Returns

A task that completes with true when the transaction was pending and is now canceled.

DeselectAsync

Method

Queues GemEndpoint.Deselect on the worker thread to send an HSMS Deselect.req control message.

public Task<HsmsToken> DeselectAsync(CancellationToken cancellationToken = default)

The command runs on the worker thread, which owns the endpoint. The task faults with PdcommException (PdcommStatus.Backpressure) when the command queue or its byte budget is full or when the command runs while event output is blocked because the event buffer is full, faults with ObjectDisposedException after the worker stopped accepting commands, and is canceled when cancellationToken is canceled before the command runs. Otherwise it carries any exception of GemEndpoint.Deselect.

Parameters

NameDescription
cancellationTokenA token that cancels the command if it has not run yet.

Returns

A task that completes with the token of the control transaction.

DisposeAsync

Method

Stops the worker, releases the endpoint and waits for the worker thread to exit.

public ValueTask DisposeAsync()

The worker stops accepting commands; queued commands that have not run fail with ObjectDisposedException. Buffered events and events read during shutdown are disposed without being delivered; events already delivered stay valid and remain owned by the reader. The worker stops the transport and waits up to HsmsWorkerOptions.ShutdownTimeoutMilliseconds for it to close. When the worker ended with a failure, such as TimeoutException at the shutdown deadline or an earlier terminal error, the returned task rethrows it after the thread has exited.

Returns

A task that completes after the worker thread exited and buffered events were discarded.

GetLocalAddressAsync

Method

Queues GemEndpoint.GetLocalAddress on the worker thread.

public Task<string> GetLocalAddressAsync(CancellationToken cancellationToken = default)

The command runs on the worker thread, which owns the endpoint. The task faults with PdcommException (PdcommStatus.Backpressure) when the command queue or its byte budget is full, faults with ObjectDisposedException after the worker stopped accepting commands, and is canceled when cancellationToken is canceled before the command runs. Otherwise it carries any exception of GemEndpoint.GetLocalAddress.

Parameters

NameDescription
cancellationTokenA token that cancels the command if it has not run yet.

Returns

A task that completes with the numeric local socket address.

GetStateAsync

Method

Queues GemEndpoint.GetState on the worker thread.

public Task<GemState> GetStateAsync(CancellationToken cancellationToken = default)

The command runs on the worker thread, which owns the endpoint. The task faults with PdcommException (PdcommStatus.Backpressure) when the command queue or its byte budget is full, faults with ObjectDisposedException after the worker stopped accepting commands, and is canceled when cancellationToken is canceled before the command runs. Otherwise it carries any exception of GemEndpoint.GetState.

Parameters

NameDescription
cancellationTokenA token that cancels the command if it has not run yet.

Returns

A task that completes with a snapshot of the GEM state.

GetTransportStateAsync

Method

Queues GemEndpoint.GetTransportState on the worker thread.

public Task<HsmsState> GetTransportStateAsync(CancellationToken cancellationToken = default)

The command runs on the worker thread, which owns the endpoint. The task faults with PdcommException (PdcommStatus.Backpressure) when the command queue or its byte budget is full, faults with ObjectDisposedException after the worker stopped accepting commands, and is canceled when cancellationToken is canceled before the command runs. Otherwise it carries any exception of GemEndpoint.GetTransportState.

Parameters

NameDescription
cancellationTokenA token that cancels the command if it has not run yet.

Returns

A task that completes with the HSMS connection state.

IsPendingAsync

Method

Queues GemEndpoint.IsPending on the worker thread.

public Task<bool> IsPendingAsync(HsmsToken token, CancellationToken cancellationToken = default)

The command runs on the worker thread, which owns the endpoint. The task faults with PdcommException (PdcommStatus.Backpressure) when the command queue or its byte budget is full, faults with ObjectDisposedException after the worker stopped accepting commands, and is canceled when cancellationToken is canceled before the command runs. Otherwise it carries any exception of GemEndpoint.IsPending.

Parameters

NameDescription
tokenThe token returned when the request was submitted.
cancellationTokenA token that cancels the command if it has not run yet.

Returns

A task that completes with true when the transaction is still pending.

LinktestAsync

Method

Queues GemEndpoint.Linktest on the worker thread to send an HSMS Linktest.req control message.

public Task<HsmsToken> LinktestAsync(CancellationToken cancellationToken = default)

The command runs on the worker thread, which owns the endpoint. The task faults with PdcommException (PdcommStatus.Backpressure) when the command queue or its byte budget is full or when the command runs while event output is blocked because the event buffer is full, faults with ObjectDisposedException after the worker stopped accepting commands, and is canceled when cancellationToken is canceled before the command runs. Otherwise it carries any exception of GemEndpoint.Linktest.

Parameters

NameDescription
cancellationTokenA token that cancels the command if it has not run yet.

Returns

A task that completes with the token of the control transaction.

ReadEventsAsync

Method

Reads the GEM events produced by the worker thread, in order.

public IAsyncEnumerable<GemEvent> ReadEventsAsync(CancellationToken cancellationToken = default)

Reading an event frees its space in the event buffer. Several enumerations can run at once; each event is delivered to only one of them. The sequence ends after the worker thread exits and every buffered event was read; when the worker failed, the enumeration then throws the exception reported by GemWorker.Completion. Events still buffered when GemWorker.DisposeAsync runs are disposed without being delivered.

Parameters

NameDescription
cancellationTokenA token that ends the enumeration.

Returns

An asynchronous sequence of events; the caller owns each GemEvent and must dispose it.

Notes

  • Throws OperationCanceledException: cancellationToken was canceled during the enumeration.

ReplyRawAsync

Method

Queues GemEndpoint.ReplyRaw on the worker thread to send a raw SECS-II reply.

public Task ReplyRawAsync(HsmsEvent primary, byte stream, byte function, bool replyExpected, ReadOnlyMemory<byte> body, CancellationToken cancellationToken = default)

The worker keeps primary alive until the command completes, so the caller may dispose it after this method returns. The body is copied before the method returns; the primary and reply body lengths count against the command byte budget. The command runs on the worker thread, which owns the endpoint. The task faults with PdcommException (PdcommStatus.Backpressure) when the command queue or its byte budget is full or when the command runs while event output is blocked because the event buffer is full, faults with ObjectDisposedException after the worker stopped accepting commands, and is canceled when cancellationToken is canceled before the command runs. Otherwise it carries any exception of GemEndpoint.ReplyRaw.

Parameters

NameDescription
primaryThe received primary event to answer, typically GemEvent.TransportEvent of an GemResultKind.Unhandled result.
streamThe SECS-II stream number of the reply.
functionThe SECS-II function number of the reply, or 0 to abort the transaction.
replyExpectedWhether the reply sets the reply-expected (W) bit; replies normally do not.
bodyOne complete encoded SECS-II item, or empty for a header-only reply.
cancellationTokenA token that cancels the command if it has not run yet.

Returns

A task that completes when the reply is accepted by the transport.

Notes

  • Throws ArgumentNullException: primary is null.
  • Throws ObjectDisposedException: primary was disposed.
  • Throws OperationCanceledException: cancellationToken is already canceled.
  • Throws PdcommException: PdcommStatus.LimitExceeded when body is longer than HsmsOptions.MaxFrameBytes minus the 14-byte frame overhead, or a nonempty body is longer than the transport SecsLimits.MessageBytes.

RequestRawAsync

Method

Queues GemEndpoint.RequestRaw on the worker thread to send a raw SECS-II primary message.

public Task<HsmsToken> RequestRawAsync(byte stream, byte function, bool replyExpected, ReadOnlyMemory<byte> body, CancellationToken cancellationToken = default)

The body is copied before the method returns and counts against the command byte budget. The command runs on the worker thread, which owns the endpoint. The task faults with PdcommException (PdcommStatus.Backpressure) when the command queue or its byte budget is full or when the command runs while event output is blocked because the event buffer is full, faults with ObjectDisposedException after the worker stopped accepting commands, and is canceled when cancellationToken is canceled before the command runs. Otherwise it carries any exception of GemEndpoint.RequestRaw.

Parameters

NameDescription
streamThe SECS-II stream number.
functionThe SECS-II function number; primary messages use odd numbers.
replyExpectedWhether the message sets the reply-expected (W) bit.
bodyOne complete encoded SECS-II item, or empty for a header-only message.
cancellationTokenA token that cancels the command if it has not run yet.

Returns

A task that completes with the token of the request once the transport accepts it.

Notes

  • Throws PdcommException: PdcommStatus.LimitExceeded when body is longer than HsmsOptions.MaxFrameBytes minus the 14-byte frame overhead, or a nonempty body is longer than the transport SecsLimits.MessageBytes.

SelectAsync

Method

Queues GemEndpoint.Select on the worker thread to send an HSMS Select.req control message.

public Task<HsmsToken> SelectAsync(CancellationToken cancellationToken = default)

The command runs on the worker thread, which owns the endpoint. The task faults with PdcommException (PdcommStatus.Backpressure) when the command queue or its byte budget is full or when the command runs while event output is blocked because the event buffer is full, faults with ObjectDisposedException after the worker stopped accepting commands, and is canceled when cancellationToken is canceled before the command runs. Otherwise it carries any exception of GemEndpoint.Select.

Parameters

NameDescription
cancellationTokenA token that cancels the command if it has not run yet.

Returns

A task that completes with the token of the control transaction.

StopAsync

Method

Queues a graceful stop of the transport on the worker thread.

public Task StopAsync(CancellationToken cancellationToken = default)

Commands queued earlier run first. After the stop starts, the worker keeps running commands and delivering events until the transport is closed, every native event was read, no event waits for buffer space, and no command is pending; then the thread exits. Keep reading events with GemWorker.ReadEventsAsync so that the drain can finish. If it does not finish within HsmsWorkerOptions.ShutdownTimeoutMilliseconds, GemWorker.Completion faults with TimeoutException.

The task faults with PdcommException (PdcommStatus.Backpressure) when the command queue is full, faults with ObjectDisposedException after the worker stopped accepting commands, and is canceled when cancellationToken is canceled before the command runs.

Parameters

NameDescription
cancellationTokenA token that cancels the command if it has not run yet.

Returns

A task that completes when the worker thread has started closing the transport, not when the worker has finished; await GemWorker.Completion for that.

Completion

Property

Gets a task that completes when the worker thread exits.

public Task Completion { get; }

The task completes successfully after a graceful stop or a disposal that finished in time. It faults with the exception that ended the worker: TimeoutException when the transport did not close and drain within HsmsWorkerOptions.ShutdownTimeoutMilliseconds after the stop started, or the exception raised by the endpoint, for example PdcommException with PdcommStatus.Poisoned.

FormattedPrograms

Property

Gets the asynchronous formatted process program operations of this worker.

public GemFormattedProgramsWorker FormattedPrograms { get; }

Every access creates a new lightweight object that needs no disposal. Its methods run the matching GemFormattedPrograms methods on the worker's polling thread. When the loaded native library lacks the formatted process program exports, each queued command fails with NotSupportedException. Enable the services at startup with GemHostWorker.StartWithFormattedProgramsAsync or GemEquipmentWorker.StartWithFormattedProgramsAsync.

Returns

A new GemFormattedProgramsWorker that queues commands on this worker.

LocalAddress

Property

Gets the numeric local socket address while the transport is listening or connected, or null otherwise.

public string? LocalAddress { get; }

For a passive endpoint the address is available when the start task completes.