Querying ProcessState - go

I have a simple program and runs an exe and checks the Exited value afterwards, but it is giving me an "panic: runtime error: invalid memory address or nil pointer dereference" error, any idea why?
package main
import (
"fmt"
"os/exec"
"time"
)
func main() {
prog:= exec.Command("path\to\exe")
prog.Dir = "path\to"
go prog.Run()
fmt.Println(prog.ProcessState.Exited())
time.Sleep(500 * time.Second)
}

The documentation says:
ProcessState contains information about an exited process available after a call to Wait or Run.
The main goroutine accesses the ProcessState field before the field is set to a non-nil value by the call to Run() in the goroutine. The call to Exited() panics as a result.
A simple fix is to call Run() from the main goroutine.

Related

Is the main function run a goroutine?

Is the main() function a goroutine? For example, I've seen a crash stack trace like the below, which makes me ask:
goroutine 1 [running]: main.binarySearch(0x0, 0x61, 0x43,
0xc420043e70, 0x19, 0x19, 0x10)
/home/---/go/src/github.com/----/sumnum.go:22 +0x80 main.main()
/home/---/go/src/github.com/---/sumnum.go:13 +0xc1 exit status 2
Is the main function a goroutine?
No.
The main function is a function.
In contrast,
A goroutine is a lightweight thread of execution. (source).
So goroutines execute functions, but goroutines are not functions, and there is not a 1-to-1 relationship between goroutines and functions.
However...
The main() function is executed in the first (and at startup, only) goroutine, goroutine #1.
But as soon as that function calls another function, then the main goroutine is no longer executing the main function, and is instead executing some other function.
So it's clear that a goroutine and a function are entirely different entities.
Do not conflate goroutines with functions!!
Functions and goroutines are entirely different concepts. And thinking of them as the same thing will lead to countless confusion and problems.
Yes, the main function runs as a goroutine (the main one).
According to https://tour.golang.org/concurrency/1
A goroutine is a lightweight thread managed by the Go runtime.
go f(x, y, z)
starts a new goroutine running f(x, y, z) The evaluation of f, x, y, and z happens in the current goroutine and the execution of f happens in the new goroutine.
Goroutines run in the same address space, so access to shared memory must be synchronized. The sync package provides useful primitives, although you won't need them much in Go as there are other primitives.
So according to this official document the main is the current goroutine.
To be precise (literally) we could address the main as the current goroutine, so simply speaking it is a goroutine. (Note: Literally speaking the main() is a function which could run as a goroutine.)
Now let's count the number of goroutines using runtime.NumGoroutine():
As an example let's run 3 goroutines. Try it online:
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
fmt.Println(runtime.NumGoroutine()) // 3
time.Sleep(100 * time.Millisecond)
}
func init() {
go main()
go main()
}
Here the current goroutine runs the new goroutine, so here we have more than one goroutine, which executes main() again. Try it online:
package main
import (
"fmt"
"runtime"
"sync/atomic"
"time"
)
func main() {
fmt.Println(runtime.NumGoroutine()) // 1 2 3 4
if atomic.LoadInt32(&i) <= 0 {
return
}
atomic.AddInt32(&i, -1)
go main()
time.Sleep(100 * time.Millisecond)
}
var i int32 = 3
Output:
1
2
3
4
Here we have one main goroutine plus 3 user called main goroutines, so total number of goroutines are 4 here.
Let's calculate factorial using main() (one goroutine - no synchronization needed). Try it online:
package main
import "fmt"
func main() {
if f <= 0 {
fmt.Println(acc)
return
}
acc *= f
f--
main()
}
var f = 5
var acc = 1
Output:
120
Note: The codes above are just for clearly showing my viewpoints and is not good for production use (Using global variables should not be the first choice).
Yes. Main func can spawn other goroutines, but "main" itself is one groutine.
package main
import (
"fmt"
"runtime"
)
func main() {
// Goroutine num includes main processing
fmt.Println(runtime.NumGoroutine()) // 1
// Spawn two goroutines
go func() {}()
go func() {}()
// Total three goroutines run
fmt.Println(runtime.NumGoroutine()) // 3
}

Wait for a non child Process to end

Hi I am working on a simple code that will monitor a process and restart the process in case the process crashes. I have written a small sample code.
This is my external process
package main
import (
"fmt"
"time"
)
func main() {
for {
time.Sleep(1000 * time.Millisecond)
fmt.Println("hello")
}
}
This is the code that monitors it.
package main
import (
"fmt"
"os"
)
func main() {
p, e := os.FindProcess(<processid>)
fmt.Println(e)
fmt.Println(p.Wait())
fmt.Println("done")
}
The challenge here is that since the first process is not a child process of the second one, it does not wait and directly exits.
Please let me know if anyone has any ideas around this.
Thanks.
Monitoring process exits because p.Wait() does not block.
From the docs:
On most operating systems, the Process must be a child of the current
process or an error will be returned.
You can perhaps poll the process pool to check if the process still exists.

How to implement a PHP function `die()` (or `exit()`) in Go?

In PHP, die() is used to stop running the script for preventing the unexpected behaviour. In Go, what is the idiomatic way to die a handle function? panic() or return?
You should use os.Exit.
Exit causes the current program to exit with the given status code.
Conventionally, code zero indicates success, non-zero an error. The
program terminates immediately; deferred functions are not run.
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("Start")
os.Exit(1)
fmt.Println("End")
}
Even, you can use panic, it's also stop normal execution but throw Error when execution stop.
The panic built-in function stops normal execution of the current
goroutine. When a function F calls panic, normal execution of F stops
immediately. Any functions whose execution was deferred by F are run
in the usual way, and then F returns to its caller. To the caller G,
the invocation of F then behaves like a call to panic, terminating G's
execution and running any deferred functions. This continues until all
functions in the executing goroutine have stopped, in reverse order.
At that point, the program is terminated and the error condition is
reported, including the value of the argument to panic. This
termination sequence is called panicking and can be controlled by the
built-in function recover.
package main
import "fmt"
func main() {
fmt.Println("Start")
panic("exit")
fmt.Println("End")
}
If you don't want to print a stack trace after exiting the program, you can use os.Exit. Also you are able to set a specific exit code with os.Exit.
Example (https://play.golang.org/p/XhDkKMhtpm):
package main
import (
"fmt"
"os"
)
func foo() {
fmt.Println("bim")
os.Exit(1)
fmt.Println("baz")
}
func main() {
foo()
foo()
}
Also be aware, that os.Exit immediately stops the program and doesn't run any deferred functions, while panic() does. See https://play.golang.org/p/KjGFZzTrJ7 and https://play.golang.org/p/Q4iciT35kP.
You can use panic in HTTP handler. Server will handle it. See Handler.
If ServeHTTP panics, the server (the caller of ServeHTTP) assumes that the effect of the panic was isolated to the active request. It recovers the panic, logs a stack trace to the server error log, and hangs up the connection.
Function panic is reserved for the situation when program just cannot continue. Inability to serve just one request is not the same as inability to continue to work, so I would log the error, set a correct HTTP status and use return. See Effective Go.
The usual way to report an error to a caller is to return an error as an extra return value. The canonical Read method is a well-known instance; it returns a byte count and an error. But what if the error is unrecoverable? Sometimes the program simply cannot continue.
The idiomatic way to break a function in Go is to use panic(). This is the defacto way to stop the execution of an event on runtime. If you want to recover the panic you can use the built in recover() function.
Panic explanation:
Panic is a built-in function that stops the ordinary flow of control
and begins panicking. When the function F calls panic, execution of F
stops, any deferred functions in F are executed normally, and then F
returns to its caller.
https://blog.golang.org/defer-panic-and-recover
Recover explanation:
Recover is a built-in function that regains control of a panicking
goroutine. Recover is only useful inside deferred functions. During
normal execution, a call to recover will return nil and have no other
effect. If the current goroutine is panicking, a call to recover will
capture the value given to panic and resume normal execution.
https://blog.golang.org/defer-panic-and-recover
And here is a simple example:
package main
import "fmt"
func badCall() {
panic("Bad call happend!")
}
func test() {
defer func() {
if err := recover(); err != nil {
fmt.Printf("Panicking %s\n\r", err)
}
}()
badCall()
fmt.Println("This is never executed!!")
}
func main() {
fmt.Println("Start testing")
test()
fmt.Println("End testing")
}

Correct way to set Exit Code of Process?

In Go what is the proper way to set the exit code of the process?
I tried changing main func to
func main() int {
return -1
}
But this causes error func main must have no arguments and no return values
OK so there is os.Exit(code int), however this immediately aborts the process and does not exit cleanly (no deferreds are run for example).
I also found that panic will exit process and set status code to nonzero, this may be the best way, although it dumps a stack trace to console.
What is the right way to set the exit code?
Make os.Exit the last deferred function executed. Deferred functions are executed immediately before the surrounding function returns, in the reverse order they were deferred. For example,
package main
import (
"fmt"
"os"
)
func main() {
code := 0
defer func() {
os.Exit(code)
}()
defer func() {
fmt.Println("Another deferred func")
}()
fmt.Println("Hello, 世界")
code = 1
}
Output:
Hello, 世界
Another deferred func
[process exited with non-zero status]
Go Playground:
http://play.golang.org/p/o0LfisANwb
The Go Programming Language Specification
Defer statements
A "defer" statement invokes a function whose execution is deferred to
the moment the surrounding function returns, either because the
surrounding function executed a return statement, reached the end of
its function body, or because the corresponding goroutine is
panicking.
DeferStmt = "defer" Expression .
The expression must be a function or method call; it cannot be
parenthesized. Calls of built-in functions are restricted as for
expression statements.
Each time the "defer" statement executes, the function value and
parameters to the call are evaluated as usual and saved anew but the
actual function body is not executed. Instead, deferred functions are
executed immediately before the surrounding function returns, in the
reverse order they were deferred.

How to declare runtime.LockOSThread() and runtime.UnlockOSThread()

I could not able to find how to declare runtime.LockOSThread() and runtime.UnlockOSThread(). I define it like [runtime.LockOSThread()] some code [runtime.UnlockOSThread()]. But it is giving error,undefined: runtime.LockOSThread and undefined: runtime.UnlockOSThread. Can anybody suggest me how to define it ? For more, I define it like,
Routine 1 {
runtime.LockOSThread()
do something
runtime.UnlockOSThread
}
main {
routine1
}
For example,
package main
import "runtime"
func routine() {
runtime.LockOSThread()
runtime.UnlockOSThread()
}
func main() {
go routine()
}
When in doubt, refer to the documentation.
func LockOSThread()
LockOSThread wires the calling goroutine to its current operating system thread.
Until the calling goroutine exits or calls UnlockOSThread, it will always execute in
that thread, and no other goroutine can.
func UnlockOSThread()
UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
If the calling goroutine has not called LockOSThread, UnlockOSThread is a no-op.

Resources