forked from microsoft/hcsshim
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Hamza El-Saawy <hamzaelsaawy@microsoft.com>
- Loading branch information
Showing
31 changed files
with
1,578 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
//go:build windows | ||
|
||
package computecore | ||
|
||
import "golang.org/x/sys/windows" | ||
|
||
// Callback functions must be converted to a uintptr via [windows.NewCallback] before being | ||
// passed to a syscall. | ||
// | ||
// Additionally, [windows.NewCallback] expects functions to return a uintptr result, | ||
// so callbacks must be modified ahead of time. | ||
// | ||
// Create a dedicated type uintptr for each callback to ensure type safety. | ||
|
||
type ( | ||
// Function type for the completion callback of an operation. | ||
// | ||
// typedef void (CALLBACK *HCS_OPERATION_COMPLETION)( | ||
// _In_ HCS_OPERATION operation, | ||
// _In_opt_ void* context | ||
// ); | ||
HCSOperationCompletion func(op HCSOperation, hcsCtx HCSContext) | ||
|
||
hcsOperationCompletionUintptr uintptr | ||
) | ||
|
||
func (f HCSOperationCompletion) asCallback() hcsOperationCompletionUintptr { | ||
if f == nil { | ||
return hcsOperationCompletionUintptr(0) | ||
} | ||
return hcsOperationCompletionUintptr(windows.NewCallback( | ||
func(op HCSOperation, hcsCtx HCSContext) uintptr { | ||
f(op, hcsCtx) | ||
return 0 | ||
}, | ||
)) | ||
} | ||
|
||
type ( | ||
// Function type for compute system event callbacks. | ||
// | ||
// typedef void (CALLBACK *HCS_EVENT_CALLBACK)( | ||
// _In_ HCS_EVENT* event, | ||
// _In_opt_ void* context | ||
// ); | ||
HCSEventCallback func(event *HCSEvent, hcsCx HCSContext) | ||
|
||
hcsEventCallbackUintptr uintptr | ||
) | ||
|
||
func (f HCSEventCallback) asCallback() hcsEventCallbackUintptr { | ||
if f == nil { | ||
return hcsEventCallbackUintptr(0) | ||
} | ||
|
||
return hcsEventCallbackUintptr(windows.NewCallback( | ||
// NewCallback expects a function with one uintptr-sized result | ||
func(event *HCSEvent, hcsCtx HCSContext) uintptr { | ||
f(event, hcsCtx) | ||
return 0 | ||
}, | ||
)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
//go:build windows | ||
|
||
package computecore | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"strings" | ||
|
||
"go.opencensus.io/trace" | ||
"golang.org/x/sys/windows" | ||
|
||
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" | ||
"github.com/Microsoft/hcsshim/internal/interop" | ||
"github.com/Microsoft/hcsshim/internal/log" | ||
"github.com/Microsoft/hcsshim/internal/oc" | ||
"github.com/Microsoft/hcsshim/internal/timeout" | ||
) | ||
|
||
// TODO: HcsSetComputeSystemCallback & HcsSetProcessCallback | ||
|
||
type ( | ||
// Handle to a compute system. | ||
HCSSystem windows.Handle | ||
|
||
// Handle to a process running in a compute system. | ||
HCSProcess windows.Handle | ||
) | ||
|
||
// HCSContext corresponds to a `void* context` parameter that allows for an arbitrary payload | ||
// containing compute system-, process-, or operation-specific data to be passed to callbacks. | ||
// | ||
// It is not compatible with [context.Context]. | ||
type HCSContext uintptr | ||
|
||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go ./*.go | ||
|
||
// HRESULT WINAPI | ||
// HcsEnumerateComputeSystems( | ||
// _In_opt_ PCWSTR query, | ||
// _In_ HCS_OPERATION operation | ||
// ); | ||
// | ||
//sys hcsEnumerateComputeSystems(query string, operation HCSOperation) (hr error) = computecore.HcsEnumerateComputeSystems? | ||
|
||
func EnumerateComputeSystems(ctx context.Context, op HCSOperation, query *hcsschema.SystemQuery) (properties []hcsschema.Properties, err error) { | ||
ctx, cancel := context.WithTimeout(ctx, timeout.SyscallWatcher) | ||
defer cancel() | ||
|
||
ctx, span := oc.StartSpan(ctx, "computecore::HcsEnumerateComputeSystems", oc.WithClientSpanKind) | ||
defer func() { | ||
if len(properties) != 0 { | ||
span.AddAttributes(trace.StringAttribute("properties", log.Format(ctx, properties))) | ||
} | ||
oc.SetSpanStatus(span, err) | ||
span.End() | ||
}() | ||
|
||
q := "" | ||
if query != nil { | ||
q, err = encode(query) | ||
if err != nil { | ||
return nil, err | ||
} | ||
span.AddAttributes(trace.StringAttribute("query", q)) | ||
} | ||
|
||
return runOperation[[]hcsschema.Properties]( | ||
ctx, | ||
op, | ||
func(_ context.Context, op HCSOperation) (err error) { | ||
return hcsEnumerateComputeSystems(q, op) | ||
}, | ||
) | ||
} | ||
|
||
// HRESULT WINAPI | ||
// HcsSetComputeSystemCallback( | ||
// _In_ HCS_SYSTEM computeSystem, | ||
// _In_ HCS_EVENT_OPTIONS callbackOptions, | ||
// _In_opt_ const void* context, | ||
// _In_ HCS_EVENT_CALLBACK callback | ||
// ); | ||
// | ||
//sys hcsSetComputeSystemCallback(computeSystem HCSSystem, callbackOptions HCSEventOptions, context HCSContext, callback hcsEventCallbackUintptr) (hr error) = computecore.HcsSetComputeSystemCallback? | ||
|
||
// SetCallback assigns a callback to handle events for the compute system. | ||
func (s HCSSystem) SetCallback(ctx context.Context, options HCSEventOptions, hcsCtx HCSContext, callback HCSEventCallback) (err error) { | ||
_, span := oc.StartSpan(ctx, "computecore::HcsSetComputeSystemCallback", oc.WithClientSpanKind) | ||
defer func() { | ||
oc.SetSpanStatus(span, err) | ||
span.End() | ||
}() | ||
ptr := callback.asCallback() | ||
span.AddAttributes( | ||
trace.StringAttribute("options", options.String()), | ||
trace.Int64Attribute("handle", int64(s)), | ||
trace.Int64Attribute("context", int64(hcsCtx)), | ||
trace.Int64Attribute("callback", int64(ptr)), | ||
) | ||
|
||
return hcsSetComputeSystemCallback(s, options, hcsCtx, ptr) | ||
} | ||
|
||
// HRESULT WINAPI | ||
// HcsSetProcessCallback( | ||
// _In_ HCS_PROCESS process, | ||
// _In_ HCS_EVENT_OPTIONS callbackOptions, | ||
// _In_ void* context, | ||
// _In_ HCS_EVENT_CALLBACK callback | ||
// ); | ||
// | ||
//sys hcsSetProcessCallback(process HCSProcess, callbackOptions HCSEventOptions, context HCSContext, callback hcsEventCallbackUintptr) (hr error) = computecore.HcsSetProcessCallback? | ||
|
||
// SetCallback assigns a callback to handle events for the compute system. | ||
func (p HCSProcess) SetCallback(ctx context.Context, options HCSEventOptions, hcsCtx HCSContext, callback HCSEventCallback) (err error) { | ||
_, span := oc.StartSpan(ctx, "computecore::HcsSetProcessCallback", oc.WithClientSpanKind) | ||
defer func() { | ||
oc.SetSpanStatus(span, err) | ||
span.End() | ||
}() | ||
ptr := callback.asCallback() | ||
span.AddAttributes( | ||
trace.StringAttribute("options", options.String()), | ||
trace.Int64Attribute("handle", int64(p)), | ||
trace.Int64Attribute("context", int64(hcsCtx)), | ||
trace.Int64Attribute("callback", int64(ptr)), | ||
) | ||
|
||
return hcsSetProcessCallback(p, options, hcsCtx, ptr) | ||
} | ||
|
||
func runOperation[T any]( | ||
ctx context.Context, | ||
op HCSOperation, | ||
f func(context.Context, HCSOperation) error, | ||
) (v T, err error) { | ||
if err := f(ctx, op); err != nil { | ||
return v, err | ||
} | ||
|
||
result, err := op.WaitForOperationResult(ctx) | ||
if err != nil { | ||
// WaitForOperationResult should (attempt to) parse result as [hcsschema.ResultError] | ||
// so just return results | ||
return v, err | ||
} | ||
err = json.Unmarshal([]byte(result), &v) | ||
return v, err | ||
} | ||
|
||
// bufferToString converts the `PWSTR` buffer to a string, and then frees the original buffer. | ||
func bufferToString(buffer *uint16) string { | ||
if buffer == nil { | ||
return "" | ||
} | ||
return interop.ConvertAndFreeCoTaskMemString(buffer) | ||
} | ||
|
||
func encode(v any) (string, error) { | ||
// TODO: pool of encoders/buffers | ||
buf := &bytes.Buffer{} | ||
enc := json.NewEncoder(buf) | ||
enc.SetEscapeHTML(false) | ||
enc.SetIndent("", "") | ||
|
||
if err := enc.Encode(v); err != nil { | ||
return "", fmt.Errorf("json encoding: %w", err) | ||
} | ||
|
||
// encoder.Encode appends a newline to the end | ||
return strings.TrimSpace(buf.String()), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// This package provides bindings and utility functions for dealing with ComputeCore.dll Win32 APIs. | ||
// | ||
// The HCS APIs allow using the operation as a future (and waiting or polling via | ||
// [HcsWaitForOperationResult] or [HcsGetOperationResult], respectively), or setting an operation | ||
// callback. | ||
// However: | ||
// | ||
// 1. Futures do not match Go's async model (which instead relies on go routines). | ||
// 2. An operation callback will error if the compute system has an event callback, which | ||
// would prevent users from relying on the latter to be notified of compute systems events. | ||
// | ||
// For that reason, the APIs are called synchronously, and can be used asynchronously using a goroutine. | ||
// | ||
// See HCS [operation samples] for more information. | ||
// | ||
// [HcsWaitForOperationResult]: https://learn.microsoft.com/en-us/virtualization/api/hcs/reference/hcswaitforoperationresult | ||
// [HcsGetOperationResult]: https://learn.microsoft.com/en-us/virtualization/api/hcs/reference/hcsgetoperationresult | ||
// [operation samples]: https://learn.microsoft.com/en-us/virtualization/api/hcs/reference/operationcompletionsample | ||
package computecore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
//go:build windows | ||
|
||
package computecore | ||
|
||
// typedef struct HCS_EVENT | ||
// { | ||
// HCS_EVENT_TYPE Type; | ||
// PCWSTR EventData; | ||
// HCS_OPERATION Operation; | ||
// } HCS_EVENT; | ||
// | ||
// https://learn.microsoft.com/en-us/virtualization/api/hcs/reference/hcs_event | ||
type HCSEvent struct { | ||
Type HCSEventType | ||
// eventData provides additional data for the event as a JSON document. | ||
// | ||
// the type of JSON document depends on the event type: | ||
// | ||
// HcsEventSystemExited github.com/Microsoft/hcsshim/internal/hcs/schema2.SystemExitStatus | ||
// HcsEventSystemCrashInitiated github.com/Microsoft/hcsshim/internal/hcs/schema2.CrashReport | ||
// HcsEventSystemCrashReport github.com/Microsoft/hcsshim/internal/hcs/schema2.CrashReport | ||
// HcsEventProcessExited github.com/Microsoft/hcsshim/internal/hcs/schema2.ProcessStatus | ||
EventData *uint16 | ||
// Handle to a completed operation, if Type is eventOperationCallback. | ||
// This is only possible when HcsSetComputeSystemCallback has specified event option HcsEventOptionEnableOperationCallbacks. | ||
Operation HCSOperation | ||
} | ||
|
||
//go:generate go run golang.org/x/tools/cmd/stringer -type=HCSEventType -trimprefix=Event event.go | ||
|
||
// HCSEventType indicates the event type for callbacks registered by hcsSetComputeSystemCallback or hcsSetProcessCallback. | ||
// | ||
// See [documentation] for more info. | ||
// | ||
// [documentation]: https://learn.microsoft.com/en-us/virtualization/api/hcs/reference/hcs_event_type | ||
type HCSEventType int32 | ||
|
||
const ( | ||
EventInvalid = HCSEventType(0x00000000) | ||
EventSystemExited = HCSEventType(0x00000001) | ||
EventSystemCrashInitiated = HCSEventType(0x00000002) | ||
EventSystemCrashReport = HCSEventType(0x00000003) | ||
EventSystemRdpEnhancedModeStateChanged = HCSEventType(0x00000004) | ||
EventSystemSiloJobCreated = HCSEventType(0x00000005) | ||
EventSystemGuestConnectionClosed = HCSEventType(0x00000006) | ||
EventProcessExited = HCSEventType(0x00010000) | ||
EventOperationCallback = HCSEventType(0x01000000) | ||
EventServiceDisconnect = HCSEventType(0x02000000) | ||
) | ||
|
||
//go:generate go run golang.org/x/tools/cmd/stringer -type=HCSEventOptions -trimprefix=EventOption event.go | ||
|
||
// HCSEventOptions defines the options for an event callback registration, used in HcsSetComputeSystemCallback and HcsSetProcessCallback. | ||
// | ||
// See [documentation] for more info. | ||
// | ||
// [documentation]: https://learn.microsoft.com/en-us/virtualization/api/hcs/reference/hcs_event_options | ||
type HCSEventOptions int32 | ||
|
||
const ( | ||
EventOptionNone = HCSEventOptions(0x00000000) | ||
EventOptionEnableOperationCallbacks = HCSEventOptions(0x00000001) | ||
) |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.