PDComm.GemWorker
Class
Provides the members shared by GemHostWorker and GemEquipmentWorker: a GEM endpoint owned by a dedicated polling thread.
public abstract class GemWorker : IAsyncDisposableThe 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
| Name | Description |
|---|---|
cancellationToken | A 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
| Name | Description |
|---|---|
token | The token returned when the request was submitted. |
cancellationToken | A 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
| Name | Description |
|---|---|
cancellationToken | A 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
| Name | Description |
|---|---|
cancellationToken | A 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
| Name | Description |
|---|---|
cancellationToken | A 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
| Name | Description |
|---|---|
cancellationToken | A 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
| Name | Description |
|---|---|
token | The token returned when the request was submitted. |
cancellationToken | A 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
| Name | Description |
|---|---|
cancellationToken | A 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
| Name | Description |
|---|---|
cancellationToken | A token that ends the enumeration. |
Returns
An asynchronous sequence of events; the caller owns each GemEvent and must dispose it.
Notes
- Throws
OperationCanceledException:cancellationTokenwas 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
| Name | Description |
|---|---|
primary | The received primary event to answer, typically GemEvent.TransportEvent of an GemResultKind.Unhandled result. |
stream | The SECS-II stream number of the reply. |
function | The SECS-II function number of the reply, or 0 to abort the transaction. |
replyExpected | Whether the reply sets the reply-expected (W) bit; replies normally do not. |
body | One complete encoded SECS-II item, or empty for a header-only reply. |
cancellationToken | A 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:primaryisnull. - Throws
ObjectDisposedException:primarywas disposed. - Throws
OperationCanceledException:cancellationTokenis already canceled. - Throws
PdcommException:PdcommStatus.LimitExceededwhenbodyis longer thanHsmsOptions.MaxFrameBytesminus the 14-byte frame overhead, or a nonempty body is longer than the transportSecsLimits.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
| Name | Description |
|---|---|
stream | The SECS-II stream number. |
function | The SECS-II function number; primary messages use odd numbers. |
replyExpected | Whether the message sets the reply-expected (W) bit. |
body | One complete encoded SECS-II item, or empty for a header-only message. |
cancellationToken | A 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.LimitExceededwhenbodyis longer thanHsmsOptions.MaxFrameBytesminus the 14-byte frame overhead, or a nonempty body is longer than the transportSecsLimits.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
| Name | Description |
|---|---|
cancellationToken | A 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
| Name | Description |
|---|---|
cancellationToken | A 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.