on how to use the go language to achieve the creation of new processes and interprocess communication, I found a lot of information on the Internet, but I have not been able to find the answer to their satisfaction, so I intend to analyze this part of the source code, and then make good use of, and share to everyone, hoping that everyone can get inspiration from it.
First, let's look at a piece of code
Proc, _: = OS. StartProcess (name, args, attr)
If err! = Nil {
Fmt. PRINTLN (ERR)
}
_, Err = Proc. Wait ()
If err! = Nil {
Fmt. PRINTLN (ERR)
}
Let's take a look at this OS. What the hell did startprocess inside? and Proc. What did Wait () do again? Go into it with me.
StartProcess starts a new process with the program, arguments and attributes
specified by name, argv and attr.
//
StartProcess is a low-level interface. The Os/exec package provides
Higher-level interfaces.
//
If There is an error, it would be of type *patherror.
Func startprocess (name string, argv []string, attr *procattr) (*process, error) {
Return startprocess (name, argv, attr)
}
The note is that this function, which provides three parameters for opening a new process, is a low-level interface, while the Os/exec wrapper provides an advanced interface. If an error occurs here, it should be a pointer-type path fault.
Next we explore what startprocess is?
Func startprocess (name string, argv []string, attr *procattr) (p *process, err error) {
Sysattr: = &syscall. procattr{
Dir:attr. Dir,
Env:attr. Env
Sys:attr. Sys,
}
For _, F: = Range attr. Files {
Sysattr. Files = Append (sysattr. Files, F.FD ())
}
PID, h, E: = Syscall. StartProcess (name, argv, sysattr)
If E! = Nil {
return nil, &patherror{"Fork/exec", Name, E}
}
Return newprocess (PID, h), nil
}
First we see sysattr being given a &syscall. Procattr pointer, what is the structure of the procattr inside this syscall, to understand it first, so that it helps to understand that we use it to start the back Syscall
Procattr holds the attributes that would be being applied to a new process
Started by startprocess.
Type procattr struct {
If Dir is Non-empty, the child changes into the directory before
Creating the process.
Dir string
If Env is Non-nil, it gives the environment variables for the
New process in the form returned by Environ.
If It is nil, the result of Environ would be used.
ENV []string
Files specifies the open files inherited by the new process. The
First three entries correspond to standard input, standard output, and
Standard error. An implementation could support additional entries,
Depending on the underlying operating system. A Nil Entry corresponds
To, file being closed when the process starts.
Files []*file
Operating system-specific process creation attributes.
Note that setting this field means the Your program
May isn't execute properly or even compile on some
Operating systems.
Sys *syscall. Sysprocattr
}
The first sentence is straightforward, stating that the PROCATTR structure contains the values of the multiple attributes used during the process of initiating the process.
1) dir is the meaning of the directory, equivalent to the new process working directory, if configured will jump directory.
2) env refers to the list of environment variables for the new process.
3) files The first three items correspond to standard input, standard output and standard error output. Each implementation can support additional entries, and if the incoming entry is nil, the file is closed when the process starts.
4) Last *syscall. Sysprocattr is a system attribute, but the author also warns that some parameters may not work in cross-platform processes.
Now let's look at the *syscall. SYSPROCATTR structure.
Type sysprocattr struct {
Chroot string//Chroot.
Credential *credential//credential.
Ptrace BOOL//Enable tracing.
SETSID BOOL//Create session.
setpgid BOOL//Set Process group ID to new PID (SYSV setpgrp)
setctty BOOL//Set controlling terminal to FD 0
noctty bool//Detach FD 0 from controlling terminal
}
Credential holds user and group identities to be assumed
By a child process started by startprocess.
Type credential struct {
Uid UInt32//User ID.
Gid UInt32//Group ID.
Groups []uint32//supplementary group IDs.
}
You can see the properties involved in this area. (Partial properties do not work across platforms)
1) Chroot
2) credential including uid\gid\groups settings
3) Some bool attributes that participate in the process of setting up a new process.
Ptrace whether to allow tracing
Setsid whether to turn on SID
Setpgid whether to set the group ID to the new process
Setctty Whether you can use terminal access
The noctty separates the terminals from the fd0.
OK, now that we've learned so much, who's going to look at the code in front of you? As follows:
Func startprocess (name string, argv []string, attr *procattr) (p *process, err error) {
Sysattr: = &syscall. procattr{
Dir:attr. Dir,
Env:attr. Env
Sys:attr. Sys,
}
For _, F: = Range attr. Files {
Sysattr. Files = Append (sysattr. Files, F.FD ())
}
PID, h, E: = Syscall. StartProcess (name, argv, sysattr)
If E! = Nil {
return nil, &patherror{"Fork/exec", Name, E}
}
Return newprocess (PID, h), nil
}
Keep watching startprocess.
Sysattr: = &syscall. procattr{
Dir:attr. Dir,
Env:attr. Env
Sys:attr. Sys,
}
Dir working directory, ENV environment variable, Sys content is given to sysattr.
For _, F: = Range attr. Files {
Sysattr. Files = Append (sysattr. Files, F.FD ())
}
The files properties are arranged to be added to the sysattr so that we can give sysattr the overall contents of the attr *procattr parameter, and see how to use this sysattr
PID, h, E: = Syscall. StartProcess (name, argv, sysattr) sysattr passed in as the third parameter to the new
Syscall. StartProcess (name, argv, sysattr)
Note: Here we notice a problem and look at the code of our early period
Proc, _: = OS. StartProcess (name, args, attr)
If err! = Nil {
Fmt. PRINTLN (ERR)
}
This line of code is very similar to our initial code, so we understand that invoking the OS startprocess is called syscall.startprocess, so we understand that syscall.startprocess belongs to the underlying call. Os. StartProcess is the upper call. Os. Startproces just wrapped a layer outside the syscall.startprocess, so we understand that when we want to create a new process, as long as the parameters are already entered, we can either use the os.startprocess to implement, or use Syscall.sta Rtprocess to achieve. It is only important to note that the objects returned by the two are not the same.
How different?
We see the OS. StartProcess returns the return newprocess (PID, h), Nil, and
Syscall. StartProcess back is PID, H, E
That means the OS. The startprocess returned is syscall. StartProcess returns the result of the wrapper for the PID and H.
Process stores the information about a process created by startprocess.
Type Process struct {
Pid int
Handle UIntPtr
Isdone UInt32//process have been successfully waited on, non zero if True
}
Func newprocess (PID int, handle uintptr) *process {
P: = &process{pid:pid, Handle:handle}
Runtime. Setfinalizer (P, (*process). Release)
Return P
}
By observing the packaging process we understand that the purpose of returning this result is to deal with problems in the process of some programs. Below we need to understand the concept of running the program.
Runtime. Setfinalizer (P, (*process). Release) What is this line doing?
This part is difficult, if you understand this part will understand why the program packaging this layer, its purpose.
The following is a large section of English. Let me try to understand.
Setfinalizer sets the finalizer associated with X to F.
When the garbage collector finds an unreachable block
With an associated finalizer, it clears the association and runs
F (x) in a separate goroutine. This makes x reachable again, but
Now without an associated finalizer. Assuming that Setfinalizer
is not called again, the next time the garbage collector sees
That's X is unreachable, it'll free X.
//
Setfinalizer (x, nil) clears any finalizer associated with X.
//
The argument x must is a pointer to an object allocated by
Calling new or by taking the address of a composite literal.
The argument f must is a function that takes a single argument
To which X's type can assigned, and can have arbitrary ignored return
Values. If either of these is not true, Setfinalizer aborts the
Program.
//
Finalizers is run in dependency order:if A points at B, both has
Finalizers, and they is otherwise unreachable, only the finalizer
for A runs; Once A is freed and the finalizer for B can run.
If a cyclic structure includes a block with a finalizer, that
Cycle isn't guaranteed to be garbage collected and the finalizer
Is isn't guaranteed to run, because there are no ordering that
respects the dependencies.
//
The finalizer for X are scheduled to run at some arbitrary time after
X becomes unreachable.
There is no guarantee that finalizers would run before a program exits,
So typically they is useful only for releasing non-memory resources
Associated with an object during a long-running program.
For example, an OS. File object could use a finalizer to close the
Associated operating system file descriptor when a program discards
An OS. File without calling Close, but it would is a mistake
To depend in a finalizer to flush an in-memory I/O buffer such as a
Bufio. Writer, because the buffer would not being flushed at program exit.
//
It isn't guaranteed that a finalizer would run if the size of *x is
Zero bytes.
//
It isn't guaranteed that a finalizer would run for objects allocated
In initializers for package-level variables. Such objects May
linker-allocated, not heap-allocated.
//
A single goroutine runs all finalizers for a program, sequentially.
If a finalizer must run for a long time, it should does so by starting
A new goroutine.
I'm not here to copy English, just for the completeness of the article, let's see what it says. First we understand that this part of the code is in the garbage collection section, so I understand that we are getting closer to the bottom, and I have a hunch that this runtime. Setfinalizer (P, (*process). Release) should be a garbage collection mechanism for this newly initiated process, that is, how we can reclaim an already-completed process or a series of garbage data generated by the process running.
This article is from the "Technical Old man" blog, please be sure to keep this source http://allragedbody.blog.51cto.com/1352220/1747146
Go language Create New process process details (OS. StartProcess Source analysis)