4545 unregisterServiceFlag bool
4646 runServiceFlag bool
4747
48- setStdHandle = windows .NewLazySystemDLL ("kernel32.dll" ).NewProc ("SetStdHandle" )
48+ kernel32 = windows .NewLazySystemDLL ("kernel32.dll" )
49+ setStdHandle = kernel32 .NewProc ("SetStdHandle" )
50+ allocConsole = kernel32 .NewProc ("AllocConsole" )
4951 oldStderr windows.Handle
5052 panicFile * os.File
5153
@@ -322,6 +324,23 @@ func registerUnregisterService(root string) (bool, error) {
322324 }
323325
324326 if runServiceFlag {
327+ // Allocate a conhost for containerd here. We don't actually use this
328+ // at all in containerd, but it will be inherited by any processes
329+ // containerd executes, so they won't need to allocate their own
330+ // conhosts. This is important for two reasons:
331+ // - Creating a conhost slows down process launch.
332+ // - We have seen reliability issues when launching many processes.
333+ // Sometimes the process invocation will fail due to an error when
334+ // creating the conhost.
335+ //
336+ // This needs to be done before initializing the panic file, as
337+ // AllocConsole sets the stdio handles to point to the new conhost,
338+ // and we want to make sure stderr goes to the panic file.
339+ r , _ , err := allocConsole .Call ()
340+ if r == 0 && err != nil {
341+ return true , fmt .Errorf ("error allocating conhost: %s" , err )
342+ }
343+
325344 if err := initPanicFile (filepath .Join (root , "panic.log" )); err != nil {
326345 return true , err
327346 }
@@ -341,7 +360,6 @@ func registerUnregisterService(root string) (bool, error) {
341360
342361 logrus .AddHook (& etwHook {log })
343362 logrus .SetOutput (ioutil .Discard )
344-
345363 }
346364 return false , nil
347365}
0 commit comments