File: main_linux.go

package info (click to toggle)
singularity-container 4.0.3%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 21,672 kB
  • sloc: asm: 3,857; sh: 2,125; ansic: 1,677; awk: 414; makefile: 110; python: 99
file content (122 lines) | stat: -rw-r--r-- 3,713 bytes parent folder | download
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()
	}
}