github.com/apptainer/singularity@v3.1.1+incompatible/cmd/starter/main.go (about)

     1  // Copyright (c) 2018-2019, Sylabs Inc. All rights reserved.
     2  // This software is licensed under a 3-clause BSD license. Please consult the
     3  // LICENSE.md file distributed with the sources of this project regarding your
     4  // rights to use or distribute this software.
     5  
     6  package main
     7  
     8  /*
     9  #include "c/message.c"
    10  #include "c/capability.c"
    11  #include "c/setns.c"
    12  #include "c/starter.c"
    13  */
    14  import "C"
    15  
    16  import (
    17  	"os"
    18  	"runtime"
    19  	"unsafe"
    20  
    21  	"github.com/sylabs/singularity/internal/app/starter"
    22  	"github.com/sylabs/singularity/internal/pkg/runtime/engines"
    23  	starterConfig "github.com/sylabs/singularity/internal/pkg/runtime/engines/config/starter"
    24  	"github.com/sylabs/singularity/internal/pkg/sylog"
    25  	"github.com/sylabs/singularity/internal/pkg/util/goversion"
    26  	"github.com/sylabs/singularity/internal/pkg/util/mainthread"
    27  )
    28  
    29  func getEngine(jsonConfig []byte) *engines.Engine {
    30  	engine, err := engines.NewEngine(jsonConfig)
    31  	if err != nil {
    32  		sylog.Fatalf("failed to initialize runtime: %s\n", err)
    33  	}
    34  	return engine
    35  }
    36  
    37  func startup() {
    38  	loglevel := os.Getenv("SINGULARITY_MESSAGELEVEL")
    39  	os.Clearenv()
    40  	if loglevel != "" {
    41  		if os.Setenv("SINGULARITY_MESSAGELEVEL", loglevel) != nil {
    42  			sylog.Warningf("can't restore SINGULARITY_MESSAGELEVEL environment variable")
    43  		}
    44  	}
    45  
    46  	cconf := unsafe.Pointer(C.config)
    47  	sconfig := starterConfig.NewConfig(starterConfig.CConfig(cconf))
    48  	jsonConfig := sconfig.GetJSONConfig()
    49  
    50  	switch C.execute {
    51  	case C.STAGE1:
    52  		sylog.Verbosef("Execute stage 1\n")
    53  		starter.Stage(int(C.STAGE1), int(C.master_socket[1]), sconfig, getEngine(jsonConfig))
    54  	case C.STAGE2:
    55  		sylog.Verbosef("Execute stage 2\n")
    56  		if err := sconfig.Release(); err != nil {
    57  			sylog.Fatalf("%s", err)
    58  		}
    59  
    60  		mainthread.Execute(func() {
    61  			starter.Stage(int(C.STAGE2), int(C.master_socket[1]), sconfig, getEngine(jsonConfig))
    62  		})
    63  	case C.MASTER:
    64  		sylog.Verbosef("Execute master process\n")
    65  
    66  		isInstance := sconfig.GetInstance()
    67  		pid := sconfig.GetContainerPid()
    68  
    69  		if err := sconfig.Release(); err != nil {
    70  			sylog.Fatalf("%s", err)
    71  		}
    72  
    73  		starter.Master(int(C.rpc_socket[0]), int(C.master_socket[0]), isInstance, pid, getEngine(jsonConfig))
    74  	case C.RPC_SERVER:
    75  		sylog.Verbosef("Serve RPC requests\n")
    76  
    77  		if err := sconfig.Release(); err != nil {
    78  			sylog.Fatalf("%s", err)
    79  		}
    80  
    81  		name := engines.GetName(jsonConfig)
    82  		starter.RPCServer(int(C.rpc_socket[1]), name)
    83  	}
    84  	sylog.Fatalf("You should not be there\n")
    85  }
    86  
    87  func init() {
    88  	// lock main thread for function execution loop
    89  	runtime.LockOSThread()
    90  	// this is mainly to reduce memory footprint
    91  	runtime.GOMAXPROCS(1)
    92  }
    93  
    94  func main() {
    95  	if err := goversion.Check(); err != nil {
    96  		sylog.Fatalf("%s", err)
    97  	}
    98  
    99  	// initialize runtime engines
   100  	engines.Init()
   101  
   102  	go startup()
   103  
   104  	// run functions requiring execution in main thread
   105  	for f := range mainthread.FuncChannel {
   106  		f()
   107  	}
   108  }