runtime: support for daemonize #227

Closed
gopherbot opened this Issue Nov 16, 2009 · 38 comments

Comments

Projects
None yet
9 participants
@gopherbot

by azummo-google@towertech.it:

(Take this as LongTerm or Thinking)

It would be fine to have a fork and daemonize calls,
something like this:

func Daemonize()
{
        os.Stdin.Close();
        os.Stdout.Close();
        os.Stderr.Close();

        pid := Fork();

        // In parent
        if pid != 0 {
                os.Exit(0);
        }

        // In child
        syscall.Setsid()

        ....
}
@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc Nov 17, 2009

Contributor

Comment 1:

Unfortunately, this is a bit harder than it looks.
On most systems, threads and daemonize do
not play well with each other.

Owner changed to r...@golang.org.

Status changed to LongTerm.

Contributor

rsc commented Nov 17, 2009

Comment 1:

Unfortunately, this is a bit harder than it looks.
On most systems, threads and daemonize do
not play well with each other.

Owner changed to r...@golang.org.

Status changed to LongTerm.

@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot Nov 17, 2009

Comment 2 by azummo-google@towertech.it:

I'm sure it is!
Here (linux/386) I'm trying daemonizing early in main()
and launching goroutine safterwards. Seems working nicely.

Comment 2 by azummo-google@towertech.it:

I'm sure it is!
Here (linux/386) I'm trying daemonizing early in main()
and launching goroutine safterwards. Seems working nicely.
@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc Dec 2, 2009

Contributor

Comment 3:

Labels changed: added packagechange.

Contributor

rsc commented Dec 2, 2009

Comment 3:

Labels changed: added packagechange.

@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot Apr 18, 2010

Comment 4 by graycardinalster:

Full analog of "daemon(3)"
import (
 "syscall"
 "os"
)
func daemon (nochdir, noclose int) int {
    var ret uintptr
    var err uintptr
    ret,_,err = syscall.Syscall(syscall.SYS_FORK, 0, 0, 0)
    if err != 0 { return -1 }
    switch (ret) {
        case 0:
            break
        default:
            os.Exit (0)
    }
    if syscall.Setsid () == -1 { return -1 }
    if (nochdir == 0) { os.Chdir("/") }
    if noclose == 0 {
        f, e := os.Open ("/dev/null", os.O_RDWR, 0)
        if e == nil {
            fd := f.Fd ()
            syscall.Dup2 (fd, os.Stdin.Fd ())
            syscall.Dup2 (fd, os.Stdout.Fd ())
            syscall.Dup2 (fd, os.Stderr.Fd ())
        }
    }
    return 0
}

Comment 4 by graycardinalster:

Full analog of "daemon(3)"
import (
 "syscall"
 "os"
)
func daemon (nochdir, noclose int) int {
    var ret uintptr
    var err uintptr
    ret,_,err = syscall.Syscall(syscall.SYS_FORK, 0, 0, 0)
    if err != 0 { return -1 }
    switch (ret) {
        case 0:
            break
        default:
            os.Exit (0)
    }
    if syscall.Setsid () == -1 { return -1 }
    if (nochdir == 0) { os.Chdir("/") }
    if noclose == 0 {
        f, e := os.Open ("/dev/null", os.O_RDWR, 0)
        if e == nil {
            fd := f.Fd ()
            syscall.Dup2 (fd, os.Stdin.Fd ())
            syscall.Dup2 (fd, os.Stdout.Fd ())
            syscall.Dup2 (fd, os.Stderr.Fd ())
        }
    }
    return 0
}
@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot Apr 19, 2010

Comment 5 by graycardinalster:

Is it possible to add this feature in Go?

Comment 5 by graycardinalster:

Is it possible to add this feature in Go?
@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc Apr 19, 2010

Contributor

Comment 6:

It's possible but not simple to add this feature to Go.
The implementation in comment #4 is not correct when
the program is multithreaded, as most interesting Go 
programs are.  (The parent gets all the threads and
the child gets none of them.)
Contributor

rsc commented Apr 19, 2010

Comment 6:

It's possible but not simple to add this feature to Go.
The implementation in comment #4 is not correct when
the program is multithreaded, as most interesting Go 
programs are.  (The parent gets all the threads and
the child gets none of them.)
@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot Apr 20, 2010

Comment 7 by graycardinalster:

Threads can not be copied anyway. Just use "daemon" before any go's

Comment 7 by graycardinalster:

Threads can not be copied anyway. Just use "daemon" before any go's
@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc Apr 20, 2010

Contributor

Comment 8:

There's no guarantee that you can arrange for the call to daemon
to happen before any go's.
Contributor

rsc commented Apr 20, 2010

Comment 8:

There's no guarantee that you can arrange for the call to daemon
to happen before any go's.
@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot Aug 18, 2010

Comment 9 by krmigr:

While it might be useful to have a Fork() function for other purposes, I'd suggest
omitting and discouraging any sort of Daemon()-like feature.
It's usually a mistake for a daemon to fork itself. Self-daemonizing makes life
unnecessarily hard for anyone who wants to monitor the daemon process.

Comment 9 by krmigr:

While it might be useful to have a Fork() function for other purposes, I'd suggest
omitting and discouraging any sort of Daemon()-like feature.
It's usually a mistake for a daemon to fork itself. Self-daemonizing makes life
unnecessarily hard for anyone who wants to monitor the daemon process.
@bsiegert

This comment has been minimized.

Show comment
Hide comment
@bsiegert

bsiegert Aug 19, 2010

Contributor

Comment 10:

I disagree with the last comment. Unix daemons have always worked this way. While a
well-written daemon should always have an option to disable forking and to stay in the
foreground, not providing a daemon()-like call in the language for this reason is the
wrong approach.
Contributor

bsiegert commented Aug 19, 2010

Comment 10:

I disagree with the last comment. Unix daemons have always worked this way. While a
well-written daemon should always have an option to disable forking and to stay in the
foreground, not providing a daemon()-like call in the language for this reason is the
wrong approach.
@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc Dec 9, 2011

Contributor

Comment 11:

Labels changed: added priority-later.

Contributor

rsc commented Dec 9, 2011

Comment 11:

Labels changed: added priority-later.

@extemporalgenome

This comment has been minimized.

Show comment
Hide comment
@extemporalgenome

extemporalgenome Jan 10, 2012

Comment 12:

I've run into a number of cases where, say, a given Linux distribution doesn't provide a
useful/secure/correct daemonization wrapper utility, if any at all. In this case,
self-daemonization, which is the defacto method, is assumed (and a good self-daemonizing
program will have an option to leave a pidfile and logfiles, which will make it easy to
monitor the process).  Since daemonization really only occurs in the wild during
initialization, it really ought to be called from an init function.
In order to make fork safe for daemonization, and seeing that the spec has now changed
(goroutines now *can* run during initialization), all we need to do is any one of three
things:
1) Disallow creation of os threads during initialization, where go's concurrency support
is only for concurrency, not parallelization, as Rob Pike might say -- all goroutine
switching during init would probably need to be cooperative (through blocking or
runtime.Gosched), which may not be possible to accomplish in the current runtime.
2) Create something like a runtime.SuspendAll() function, upon returning, guarantees
that all other threads are muxed off of os threads (which are destroyed) and the calling
goroutine is run alone until a complimentary function, like a runtime.ResumeAll() is
called. This is not the same as GOMAXPROCS, which doesn't restrict the number of threads
used by the runtime (this option would need to account for those as well).
3) Amend the published spec to require that unrelated dependencies initialize in
code-order (this would also mean that gofmt wouldn't be allowed to reorder imports), or
at least that independent import groups occur in source order. So at the minimum, the
following should require that daemon initialize fully before threadspawner:
import "daemon" // daemon imports nothing
import (
  "fmt"
  "os"
  "threadspawner" // threadspawner imports nothing
)
(Binaries produced from 6g and friends appear to do this in either undefined or reverse
order).
Knowing nothing about the toolchain/runtime internals, #3 is probably the simplest to
implement -- if you want to argue that the compiler be allowed to optimize for speed
(putting goroutines-spawning initializers before non-concurrent initializers), keep in
mind that initialization is not a critical place for speed (in a long running program,
initialization time counts for nothing, and in short running programs, heavy lifting is
usually *not* done in initialization).

Comment 12:

I've run into a number of cases where, say, a given Linux distribution doesn't provide a
useful/secure/correct daemonization wrapper utility, if any at all. In this case,
self-daemonization, which is the defacto method, is assumed (and a good self-daemonizing
program will have an option to leave a pidfile and logfiles, which will make it easy to
monitor the process).  Since daemonization really only occurs in the wild during
initialization, it really ought to be called from an init function.
In order to make fork safe for daemonization, and seeing that the spec has now changed
(goroutines now *can* run during initialization), all we need to do is any one of three
things:
1) Disallow creation of os threads during initialization, where go's concurrency support
is only for concurrency, not parallelization, as Rob Pike might say -- all goroutine
switching during init would probably need to be cooperative (through blocking or
runtime.Gosched), which may not be possible to accomplish in the current runtime.
2) Create something like a runtime.SuspendAll() function, upon returning, guarantees
that all other threads are muxed off of os threads (which are destroyed) and the calling
goroutine is run alone until a complimentary function, like a runtime.ResumeAll() is
called. This is not the same as GOMAXPROCS, which doesn't restrict the number of threads
used by the runtime (this option would need to account for those as well).
3) Amend the published spec to require that unrelated dependencies initialize in
code-order (this would also mean that gofmt wouldn't be allowed to reorder imports), or
at least that independent import groups occur in source order. So at the minimum, the
following should require that daemon initialize fully before threadspawner:
import "daemon" // daemon imports nothing
import (
  "fmt"
  "os"
  "threadspawner" // threadspawner imports nothing
)
(Binaries produced from 6g and friends appear to do this in either undefined or reverse
order).
Knowing nothing about the toolchain/runtime internals, #3 is probably the simplest to
implement -- if you want to argue that the compiler be allowed to optimize for speed
(putting goroutines-spawning initializers before non-concurrent initializers), keep in
mind that initialization is not a critical place for speed (in a long running program,
initialization time counts for nothing, and in short running programs, heavy lifting is
usually *not* done in initialization).
@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc Jan 10, 2012

Contributor

Comment 13:

It is extremely unlikely that we will make a spec change
for daemonization.  We will just make it work.
Contributor

rsc commented Jan 10, 2012

Comment 13:

It is extremely unlikely that we will make a spec change
for daemonization.  We will just make it work.
@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot Jan 10, 2012

Comment 14 by cw@f00f.org:

We can make daemonize work 'as expected' with a few restrictions.
These restrictions won't apply to most people and almost never if called in or near
program start-up.
These restrictions aren't unique to Go, but we can detect and error on them rather than
silently ignore them (as is sometimes the case elsewhere).

Comment 14 by cw@f00f.org:

We can make daemonize work 'as expected' with a few restrictions.
These restrictions won't apply to most people and almost never if called in or near
program start-up.
These restrictions aren't unique to Go, but we can detect and error on them rather than
silently ignore them (as is sometimes the case elsewhere).
@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc Jan 10, 2012

Contributor

Comment 15:

The way to do it is to have a separate package
that you have to import to get Daemonize.
If you've imported that package, then the runtime
will know from the very beginning that you are
going to call it and can plan accordingly.
Russ
Contributor

rsc commented Jan 10, 2012

Comment 15:

The way to do it is to have a separate package
that you have to import to get Daemonize.
If you've imported that package, then the runtime
will know from the very beginning that you are
going to call it and can plan accordingly.
Russ
@extemporalgenome

This comment has been minimized.

Show comment
Hide comment
@extemporalgenome

extemporalgenome Jan 11, 2012

Comment 16:

Special casing a standard daemon package actually sounds like the most intuitive thing
-- thanks Russ! In any case, programmers who roll their own almost always do the wrong
thing (I think even the C daemon call doesn't handle it even close to securely), and we
shouldn't make them worry about implementation details.

Comment 16:

Special casing a standard daemon package actually sounds like the most intuitive thing
-- thanks Russ! In any case, programmers who roll their own almost always do the wrong
thing (I think even the C daemon call doesn't handle it even close to securely), and we
shouldn't make them worry about implementation details.
@extemporalgenome

This comment has been minimized.

Show comment
Hide comment
@extemporalgenome

extemporalgenome Jan 11, 2012

Comment 17:

Special casing a standard daemon package actually sounds like the most intuitive thing
-- thanks Russ! In any case, programmers who roll their own almost always do the wrong
thing (I think even the C daemon call doesn't handle it even close to securely), and we
shouldn't make them worry about implementation details.

Comment 17:

Special casing a standard daemon package actually sounds like the most intuitive thing
-- thanks Russ! In any case, programmers who roll their own almost always do the wrong
thing (I think even the C daemon call doesn't handle it even close to securely), and we
shouldn't make them worry about implementation details.
@alberts

This comment has been minimized.

Show comment
Hide comment
@alberts

alberts Apr 27, 2012

Contributor

Comment 19:

I think there is a similar problem with calling unshare inside a Go program.
Contributor

alberts commented Apr 27, 2012

Comment 19:

I think there is a similar problem with calling unshare inside a Go program.
@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc Sep 12, 2012

Contributor

Comment 20:

Labels changed: added go1.1maybe.

Contributor

rsc commented Sep 12, 2012

Comment 20:

Labels changed: added go1.1maybe.

@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot Sep 18, 2012

Comment 21 by rjmcguire:

Would your changes allow one to have multiple processes accepting socket connections for
single listening socket like C does*?
basically:
proc1: sock.listen
proc1: fork N children
procN: s = sock.accept
procN: do work on s
* on Linux this is possible not sure about other OSes

Comment 21 by rjmcguire:

Would your changes allow one to have multiple processes accepting socket connections for
single listening socket like C does*?
basically:
proc1: sock.listen
proc1: fork N children
procN: s = sock.accept
procN: do work on s
* on Linux this is possible not sure about other OSes
@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc Sep 18, 2012

Contributor

Comment 22:

That's unrelated to daemonize, although it is something 'daemons' do.
You can do that today by doing a net.Listen and then passing the
l.Fd() to multiple os.StartProcess.
Russ
Contributor

rsc commented Sep 18, 2012

Comment 22:

That's unrelated to daemonize, although it is something 'daemons' do.
You can do that today by doing a net.Listen and then passing the
l.Fd() to multiple os.StartProcess.
Russ
@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot Sep 18, 2012

Comment 23 by cw@f00f.org:

Or you could use SCM_RIGHTS after the fact.

Comment 23 by cw@f00f.org:

Or you could use SCM_RIGHTS after the fact.
@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot Sep 19, 2012

Comment 24 by rjmcguire:

Fd as args doesn't seem to work, File in Files doesn't seem to work either. UNIX sockets
are ancient (lines of code and problems).
Are there any examples that work and show passing a socket through Files to StartProcess.

Comment 24 by rjmcguire:

Fd as args doesn't seem to work, File in Files doesn't seem to work either. UNIX sockets
are ancient (lines of code and problems).
Are there any examples that work and show passing a socket through Files to StartProcess.
@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot Sep 19, 2012

Comment 25 by rjmcguire:

Thanks, using StartProcess for now.

Comment 25 by rjmcguire:

Thanks, using StartProcess for now.
@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot Sep 24, 2012

Comment 26 by matthias.benkmann:

How about this
type MainFunc func(...interface{})   
// Forks a child process and executes main(args...) within that process. 
// Returns the process id of the child.
//
// Within the child process, a new Go runtime is initialized from scratch, as
// if the program had started its own binary via os.StartProcess(). However as
// the last step instead of starting main.main(), the child process will start    
// the main function passed to Fork(). 
//
// The parameters args are passed via encoding/gob with the corresponding
// restrictions.
//
// Open file descriptors, os.Args and the environment are inherited from  
// the parent process, NOT reset to the values they had at the start of     
// the program.
//
// Note: Fork() does not actually re-execute the program's binary.
// The program's binary need not be executable for purposes of Fork()
// Fork() will succeed even if the process no longer has the necessary
// privileges to execute the binary or if it has been (re)moved.
func Fork(main MainFunc, args... interface{}) (int, error) {
...
}
This Fork() has well-defined semantics and can be used for daemonizing as well as many
other uses of fork().
Implementing the ability to set up a new runtime environment without accessing the
binary shouldn't be too tough. The compiler might have to be changed to keep an
additional read-only copy of initial values for certain structures around. But that
doesn't require changing the language spec.

Comment 26 by matthias.benkmann:

How about this
type MainFunc func(...interface{})   
// Forks a child process and executes main(args...) within that process. 
// Returns the process id of the child.
//
// Within the child process, a new Go runtime is initialized from scratch, as
// if the program had started its own binary via os.StartProcess(). However as
// the last step instead of starting main.main(), the child process will start    
// the main function passed to Fork(). 
//
// The parameters args are passed via encoding/gob with the corresponding
// restrictions.
//
// Open file descriptors, os.Args and the environment are inherited from  
// the parent process, NOT reset to the values they had at the start of     
// the program.
//
// Note: Fork() does not actually re-execute the program's binary.
// The program's binary need not be executable for purposes of Fork()
// Fork() will succeed even if the process no longer has the necessary
// privileges to execute the binary or if it has been (re)moved.
func Fork(main MainFunc, args... interface{}) (int, error) {
...
}
This Fork() has well-defined semantics and can be used for daemonizing as well as many
other uses of fork().
Implementing the ability to set up a new runtime environment without accessing the
binary shouldn't be too tough. The compiler might have to be changed to keep an
additional read-only copy of initial values for certain structures around. But that
doesn't require changing the language spec.
@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot Sep 25, 2012

Comment 27 by rjmcguire:

You can already detach from the controlling terminal by using StartProcess
and setting stdin,stdout, and stderr to nil (Only tested on ubuntu
12.04 bash in a gnome-terminal).
However we would still need a fork() approach if you wanted to
drop privileges before detaching.
Rory McGuire
Email: rjmcguire@gmail.com
Mobile: (+27)(0) 82 856 3646

Comment 27 by rjmcguire:

You can already detach from the controlling terminal by using StartProcess
and setting stdin,stdout, and stderr to nil (Only tested on ubuntu
12.04 bash in a gnome-terminal).
However we would still need a fork() approach if you wanted to
drop privileges before detaching.
Rory McGuire
Email: rjmcguire@gmail.com
Mobile: (+27)(0) 82 856 3646
@robpike

This comment has been minimized.

Show comment
Hide comment
@robpike

robpike Mar 7, 2013

Contributor

Comment 28:

Labels changed: removed go1.1maybe.

Contributor

robpike commented Mar 7, 2013

Comment 28:

Labels changed: removed go1.1maybe.

@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot Nov 18, 2013

Comment 29 by sergey.yarmonov:

You can try package https://github.com/sevlyar/go-daemon

Comment 29 by sergey.yarmonov:

You can try package https://github.com/sevlyar/go-daemon
@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc Nov 27, 2013

Contributor

Comment 30:

Labels changed: added go1.3maybe.

Contributor

rsc commented Nov 27, 2013

Comment 30:

Labels changed: added go1.3maybe.

@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc Dec 4, 2013

Contributor

Comment 31:

Labels changed: added release-none, removed go1.3maybe.

Contributor

rsc commented Dec 4, 2013

Comment 31:

Labels changed: added release-none, removed go1.3maybe.

@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc Dec 4, 2013

Contributor

Comment 32:

Labels changed: added repo-main.

Contributor

rsc commented Dec 4, 2013

Comment 32:

Labels changed: added repo-main.

@didenko didenko referenced this issue in didenko/pald May 10, 2015

Closed

Make pald friendly to daemon wrappers #7

@kkirsche kkirsche referenced this issue in elastic/beats Feb 20, 2016

Closed

start beats as a background process #984

@drewwells drewwells referenced this issue in wellington/wellington Apr 7, 2016

Closed

Support running in background #177

@akutz akutz referenced this issue in rexray/rexray May 10, 2016

Closed

Rexray can not start without "-f" #424

OlingCat added a commit to OlingCat/tour that referenced this issue May 18, 2016

fix backqoute
Fixes golang/go#227 golang/go#219

Change-Id: Iafd4173bee475b823065c8d39d094f17a87a2671

@ahmetb ahmetb referenced this issue in Azure/custom-script-extension-linux Jul 26, 2016

Closed

[todo] daemonize 'enable' #35

@cschwarz-inco

This comment has been minimized.

Show comment
Hide comment
@cschwarz-inco

cschwarz-inco Jul 28, 2016

I found those daemon packages that have emerged too complicated, here is my solution:

package main

import (
    "log"
    "os"
    "os/exec"
    "syscall"
    "time"
)

func main() {
    // check command line flags, configuration etc.

    // short delay to avoid race condition between os.StartProcess and os.Exit
    // can be omitted if the work done above amounts to a sufficient delay
    time.Sleep(1 * time.Second)

    if os.Getppid() != 1 {
        // I am the parent, spawn child to run as daemon
        binary, err := exec.LookPath(os.Args[0])
        if err != nil {
            log.Fatalln("Failed to lookup binary:", err)
        }
        _, err = os.StartProcess(binary, os.Args, &os.ProcAttr{Dir: "", Env: nil,
                Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, Sys: nil})
        if err != nil {
            log.Fatalln("Failed to start process:", err)
        }
        os.Exit(0)
    } else {
        // I am the child, i.e. the daemon, start new session and detach from terminal
        _, err := syscall.Setsid()
        if err != nil {
            log.Fatalln("Failed to create new session:", err)
        }
        file, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
        if err != nil {
            log.Fatalln("Failed to open /dev/null:", err)
        }
        syscall.Dup2(int(file.Fd()), int(os.Stdin.Fd()))
        syscall.Dup2(int(file.Fd()), int(os.Stdout.Fd()))
        syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd()))
        file.Close()
    }

    // daemon business logic starts here
}

I found those daemon packages that have emerged too complicated, here is my solution:

package main

import (
    "log"
    "os"
    "os/exec"
    "syscall"
    "time"
)

func main() {
    // check command line flags, configuration etc.

    // short delay to avoid race condition between os.StartProcess and os.Exit
    // can be omitted if the work done above amounts to a sufficient delay
    time.Sleep(1 * time.Second)

    if os.Getppid() != 1 {
        // I am the parent, spawn child to run as daemon
        binary, err := exec.LookPath(os.Args[0])
        if err != nil {
            log.Fatalln("Failed to lookup binary:", err)
        }
        _, err = os.StartProcess(binary, os.Args, &os.ProcAttr{Dir: "", Env: nil,
                Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, Sys: nil})
        if err != nil {
            log.Fatalln("Failed to start process:", err)
        }
        os.Exit(0)
    } else {
        // I am the child, i.e. the daemon, start new session and detach from terminal
        _, err := syscall.Setsid()
        if err != nil {
            log.Fatalln("Failed to create new session:", err)
        }
        file, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
        if err != nil {
            log.Fatalln("Failed to open /dev/null:", err)
        }
        syscall.Dup2(int(file.Fd()), int(os.Stdin.Fd()))
        syscall.Dup2(int(file.Fd()), int(os.Stdout.Fd()))
        syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd()))
        file.Close()
    }

    // daemon business logic starts here
}
@extemporalgenome

This comment has been minimized.

Show comment
Hide comment
@extemporalgenome

extemporalgenome Jul 28, 2016

Your race-avoidance code still forms a race condition

Your race-avoidance code still forms a race condition

@cschwarz-inco

This comment has been minimized.

Show comment
Hide comment
@cschwarz-inco

cschwarz-inco Jul 28, 2016

This should eliminate the race condition. Instead of the sleep, do:

    err := syscall.FcntlFlock(os.Stdout.Fd(), syscall.F_SETLKW, &syscall.Flock_t{
        Type: syscall.F_WRLCK, Whence: 0, Start: 0, Len: 0 })
    if err != nil {
        log.Fatalln("Failed to lock stdout:", err)
    }

cschwarz-inco commented Jul 28, 2016

This should eliminate the race condition. Instead of the sleep, do:

    err := syscall.FcntlFlock(os.Stdout.Fd(), syscall.F_SETLKW, &syscall.Flock_t{
        Type: syscall.F_WRLCK, Whence: 0, Start: 0, Len: 0 })
    if err != nil {
        log.Fatalln("Failed to lock stdout:", err)
    }
@iamybj

This comment has been minimized.

Show comment
Hide comment
@iamybj

iamybj Oct 19, 2016

This is not a bug of go.
Any programming language have a question of "threads and daemonize do
not play well with each other"
This is a question of programming logical, but not a question of programming technology.
This issue should bu closed!

iamybj commented Oct 19, 2016

This is not a bug of go.
Any programming language have a question of "threads and daemonize do
not play well with each other"
This is a question of programming logical, but not a question of programming technology.
This issue should bu closed!

@bradfitz

This comment has been minimized.

Show comment
Hide comment
@bradfitz

bradfitz Oct 19, 2016

Member

Yeah, I think it's time we finally closed this. The answer is init systems like systemd, launchd, daemontools, supervisor, runit, Kubernetes, heroku, Borg, etc etc.

Member

bradfitz commented Oct 19, 2016

Yeah, I think it's time we finally closed this. The answer is init systems like systemd, launchd, daemontools, supervisor, runit, Kubernetes, heroku, Borg, etc etc.

@bradfitz bradfitz closed this Oct 19, 2016

@robpike

This comment has been minimized.

Show comment
Hide comment
@robpike

robpike Oct 19, 2016

Contributor

Don't always need systemd, launchd, daemontools, supervisor, runit, Kubernetes, heroku, Borg, etc etc. when you have the shell's & operator.

Contributor

robpike commented Oct 19, 2016

Don't always need systemd, launchd, daemontools, supervisor, runit, Kubernetes, heroku, Borg, etc etc. when you have the shell's & operator.

@iamybj

This comment has been minimized.

Show comment
Hide comment
@iamybj

iamybj Oct 20, 2016

yes, daemonize is a OS level question, not a programming language level question.

iamybj commented Oct 20, 2016

yes, daemonize is a OS level question, not a programming language level question.

xgfone added a commit to xgfone/go-tools that referenced this issue Dec 19, 2016

@pascaldekloe pascaldekloe referenced this issue in ethereumproject/go-ethereum Feb 7, 2017

Open

Daemonize #8

@golang golang locked and limited conversation to collaborators Oct 20, 2017

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.