![dependabot[bot]](/assets/img/avatar_default.png)
Bumps the golang group with 5 updates: | Package | From | To | | --- | --- | --- | | [github.com/Microsoft/hcsshim](https://github.com/Microsoft/hcsshim) | `0.11.4` | `0.12.0` | | [github.com/alexflint/go-filemutex](https://github.com/alexflint/go-filemutex) | `1.2.0` | `1.3.0` | | [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) | `2.13.2` | `2.16.0` | | [github.com/onsi/gomega](https://github.com/onsi/gomega) | `1.30.0` | `1.31.1` | | [golang.org/x/sys](https://github.com/golang/sys) | `0.15.0` | `0.17.0` | Updates `github.com/Microsoft/hcsshim` from 0.11.4 to 0.12.0 - [Release notes](https://github.com/Microsoft/hcsshim/releases) - [Commits](https://github.com/Microsoft/hcsshim/compare/v0.11.4...v0.12.0) Updates `github.com/alexflint/go-filemutex` from 1.2.0 to 1.3.0 - [Release notes](https://github.com/alexflint/go-filemutex/releases) - [Commits](https://github.com/alexflint/go-filemutex/compare/v1.2.0...v1.3.0) Updates `github.com/onsi/ginkgo/v2` from 2.13.2 to 2.16.0 - [Release notes](https://github.com/onsi/ginkgo/releases) - [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/ginkgo/compare/v2.13.2...v2.16.0) Updates `github.com/onsi/gomega` from 1.30.0 to 1.31.1 - [Release notes](https://github.com/onsi/gomega/releases) - [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/gomega/compare/v1.30.0...v1.31.1) Updates `golang.org/x/sys` from 0.15.0 to 0.17.0 - [Commits](https://github.com/golang/sys/compare/v0.15.0...v0.17.0) --- updated-dependencies: - dependency-name: github.com/Microsoft/hcsshim dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang - dependency-name: github.com/alexflint/go-filemutex dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang - dependency-name: github.com/onsi/ginkgo/v2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang - dependency-name: github.com/onsi/gomega dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang ... Signed-off-by: dependabot[bot] <support@github.com>
115 lines
3.8 KiB
Go
115 lines
3.8 KiB
Go
//go:build windows
|
|
|
|
package jobobject
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"sync"
|
|
"unsafe"
|
|
|
|
"github.com/Microsoft/hcsshim/internal/log"
|
|
"github.com/Microsoft/hcsshim/internal/queue"
|
|
"github.com/Microsoft/hcsshim/internal/winapi"
|
|
"github.com/sirupsen/logrus"
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
var (
|
|
ioInitOnce sync.Once
|
|
initIOErr error
|
|
// Global iocp handle that will be re-used for every job object
|
|
ioCompletionPort windows.Handle
|
|
// Mapping of job handle to queue to place notifications in.
|
|
jobMap sync.Map
|
|
)
|
|
|
|
// MsgAllProcessesExited is a type representing a message that every process in a job has exited.
|
|
type MsgAllProcessesExited struct{}
|
|
|
|
// MsgUnimplemented represents a message that we are aware of, but that isn't implemented currently.
|
|
// This should not be treated as an error.
|
|
type MsgUnimplemented struct{}
|
|
|
|
// pollIOCP polls the io completion port forever.
|
|
func pollIOCP(ctx context.Context, iocpHandle windows.Handle) {
|
|
var (
|
|
overlapped uintptr
|
|
code uint32
|
|
key uintptr
|
|
)
|
|
|
|
for {
|
|
err := windows.GetQueuedCompletionStatus(iocpHandle, &code, &key, (**windows.Overlapped)(unsafe.Pointer(&overlapped)), windows.INFINITE)
|
|
if err != nil {
|
|
log.G(ctx).WithError(err).Error("failed to poll for job object message")
|
|
continue
|
|
}
|
|
if val, ok := jobMap.Load(key); ok {
|
|
msq, ok := val.(*queue.MessageQueue)
|
|
if !ok {
|
|
log.G(ctx).WithField("value", msq).Warn("encountered non queue type in job map")
|
|
continue
|
|
}
|
|
notification, err := parseMessage(code, overlapped)
|
|
if err != nil {
|
|
log.G(ctx).WithFields(logrus.Fields{
|
|
"code": code,
|
|
"overlapped": overlapped,
|
|
}).Warn("failed to parse job object message")
|
|
continue
|
|
}
|
|
if err := msq.Enqueue(notification); errors.Is(err, queue.ErrQueueClosed) {
|
|
// Write will only return an error when the queue is closed.
|
|
// The only time a queue would ever be closed is when we call `Close` on
|
|
// the job it belongs to which also removes it from the jobMap, so something
|
|
// went wrong here. We can't return as this is reading messages for all jobs
|
|
// so just log it and move on.
|
|
log.G(ctx).WithFields(logrus.Fields{
|
|
"code": code,
|
|
"overlapped": overlapped,
|
|
}).Warn("tried to write to a closed queue")
|
|
continue
|
|
}
|
|
} else {
|
|
log.G(ctx).Warn("received a message for a job not present in the mapping")
|
|
}
|
|
}
|
|
}
|
|
|
|
func parseMessage(code uint32, overlapped uintptr) (interface{}, error) {
|
|
// Check code and parse out relevant information related to that notification
|
|
// that we care about. For now all we handle is the message that all processes
|
|
// in the job have exited.
|
|
switch code {
|
|
case winapi.JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
|
|
return MsgAllProcessesExited{}, nil
|
|
// Other messages for completeness and a check to make sure that if we fall
|
|
// into the default case that this is a code we don't know how to handle.
|
|
case winapi.JOB_OBJECT_MSG_END_OF_JOB_TIME:
|
|
case winapi.JOB_OBJECT_MSG_END_OF_PROCESS_TIME:
|
|
case winapi.JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT:
|
|
case winapi.JOB_OBJECT_MSG_NEW_PROCESS:
|
|
case winapi.JOB_OBJECT_MSG_EXIT_PROCESS:
|
|
case winapi.JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS:
|
|
case winapi.JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT:
|
|
case winapi.JOB_OBJECT_MSG_JOB_MEMORY_LIMIT:
|
|
case winapi.JOB_OBJECT_MSG_NOTIFICATION_LIMIT:
|
|
default:
|
|
return nil, fmt.Errorf("unknown job notification type: %d", code)
|
|
}
|
|
return MsgUnimplemented{}, nil
|
|
}
|
|
|
|
// Assigns an IO completion port to get notified of events for the registered job
|
|
// object.
|
|
func attachIOCP(job windows.Handle, iocp windows.Handle) error {
|
|
info := winapi.JOBOBJECT_ASSOCIATE_COMPLETION_PORT{
|
|
CompletionKey: job,
|
|
CompletionPort: iocp,
|
|
}
|
|
_, err := windows.SetInformationJobObject(job, windows.JobObjectAssociateCompletionPortInformation, uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)))
|
|
return err
|
|
}
|