1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
// Copyright (c) 2018-2023, Sylabs Inc. All rights reserved.
// Copyright (c) Contributors to the Apptainer project, established as
// Apptainer a Series of LF Projects LLC.
// This software is licensed under a 3-clause BSD license. Please consult the
// LICENSE.md file distributed with the sources of this project regarding your
// rights to use or distribute this software.
package main
// Note that the inclusion of builddir here only works when mconfig -b has not
// renamed it; that is handled via a setting of CGO_CFLAGS in mconfig. It is
// included here also so that Go tools such as code editors and linters can
// find config.h when the default builddir is used.
// #cgo CFLAGS: -I${SRCDIR}/../../builddir
// #include <config.h>
// #include "c/message.c"
// #include "c/capability.c"
// #include "c/setns.c"
// #include "c/starter.c"
import "C"
import (
"runtime"
"unsafe"
"github.com/sylabs/singularity/v4/internal/app/starter"
"github.com/sylabs/singularity/v4/internal/pkg/runtime/engine"
starterConfig "github.com/sylabs/singularity/v4/internal/pkg/runtime/engine/config/starter"
"github.com/sylabs/singularity/v4/internal/pkg/util/mainthread"
"github.com/sylabs/singularity/v4/pkg/sylog"
// register engines
_ "github.com/sylabs/singularity/v4/cmd/starter/engines"
)
func getEngine(jsonConfig []byte) *engine.Engine {
e, err := engine.Get(jsonConfig)
if err != nil {
sylog.Fatalf("Failed to initialize runtime engine: %s\n", err)
}
return e
}
func startup() {
// global variable defined in cmd/starter/c/starter.c,
// C.sconfig points to a shared memory area
csconf := unsafe.Pointer(C.sconfig)
// initialize starter configuration
sconfig := starterConfig.NewConfig(starterConfig.SConfig(csconf))
// get JSON configuration originally passed from CLI
jsonConfig := sconfig.GetJSONConfig()
// get engine operations previously registered
// by the above import
e := getEngine(jsonConfig)
sylog.Debugf("%s runtime engine selected", e.EngineName)
switch C.goexecute {
case C.STAGE1:
sylog.Verbosef("Execute stage 1\n")
starter.StageOne(sconfig, e)
case C.STAGE2:
sylog.Verbosef("Execute stage 2\n")
if err := sconfig.Release(); err != nil {
sylog.Fatalf("%s", err)
}
mainthread.Execute(func() {
starter.StageTwo(int(C.master_socket[1]), e)
})
case C.MASTER:
sylog.Verbosef("Execute master process\n")
pid := sconfig.GetContainerPid()
imageFd := sconfig.GetImageFd()
if err := sconfig.Release(); err != nil {
sylog.Fatalf("%s", err)
}
starter.Master(int(C.rpc_socket[0]), int(C.master_socket[0]), int(C.cleanup_socket[0]), pid, imageFd, e)
case C.RPC_SERVER:
sylog.Verbosef("Serve RPC requests\n")
if err := sconfig.Release(); err != nil {
sylog.Fatalf("%s", err)
}
starter.RPCServer(int(C.rpc_socket[1]), e)
case C.CLEANUP_HOST:
sylog.Verbosef("Execute Cleanup Host Process")
if err := sconfig.Release(); err != nil {
sylog.Fatalf("%s", err)
}
starter.CleanupHost(int(C.cleanup_socket[1]), e)
}
sylog.Fatalf("You should not be there\n")
}
func init() {
// lock main thread for function execution loop
runtime.LockOSThread()
// this is mainly to reduce memory footprint
runtime.GOMAXPROCS(1)
}
// main function is executed after starter.c init function.
// Depending on the value of goexecute from starter.c Go will act differently,
// e.g. it may launch container process or spawn a container monitor. Thus
// Go runtime appears to be in a different environment based on the current
// execution stage.
func main() {
// spawn a goroutine to use mainthread later
go startup()
// run functions requiring execution in main thread
for f := range mainthread.FuncChannel {
f()
}
}
|