Before learning about the process control knowledge, we need to understand a single process of the operating environment.
In this chapter we will look at the following:
- How the main function is called when the program is running;
- How command-line arguments are passed into the program;
- What a typical memory layout is;
- How to allocate memory;
- How the program uses environment variables;
- The various ways in which the program terminates;
- How the Jump (longjmp and setjmp) functions work, and how to interact with the stack;
- Resource limits for processes
?
1 main function
The main function declares:
int main (int argc, char *argv[]);
Parameter description:
- ARGC: Number of command line arguments
- ARGV: Pointer to an array of parameter lists
Before the main function starts:
- The C program is executed by the kernel and called by the system exec;
- Before the main function is called, execute the specified boot path (start-up routine);
- The executable file considers this address to be the startup address of the program, which is specified by the linker;
- The boot path obtains the parameter list and environment variables from the kernel, so that the main function can get these variables at a later call.
?
2 process termination
There are 8 ways to terminate the process, 5 normal terminations and 3 abnormal terminations.
5 Kinds of normal termination:
- Returns from the main function;
- Call exit;
- Call _exit or _exit;
- The last thread returns;
- The last thread calls Pthread_exit.
3 Kinds of Abnormal termination:
- Call abort;
- to receive a signal;
- The last thread answers or one receives an exit request
The start address (start-up routine) is also the return address of the main function.
To get the address, you can do this in the following ways:
Exit (Main (ARGC, argv));
?
Exit function
function declaration:
#include <stdlib.h>
void exit (int status);
void _exit (int status);
#include <unistd.h>
void _exit (int status);
Function Details:
- _exit and _exit immediately return to the kernel;
- The Exit function will perform some cleanup work before returning to the kernel;
Returns an integer and calls the Exit function, and the effect of passing in the integer is the same:
Exit (0);
return 0;
?
atexit function
function declaration
#include <stdlib.h>
int atexit (void (*func) (void));
Function Details
- Each process can register 32 functions that can be called automatically when the main function calls exit
- The exit-time processing function registered by Atexit is called an exit handle (exit Handlers)
- The order in which these exit handles are called is the reverse order of registration
- The Exit function closes all open streams the first time it calls out of the handle
- If the main program calls the EXEC series function, all registered exit handles will be emptied
?
Program Start and stop flowchart
?
Example:
#include "Apue.h"
?
static void my_exit1 (void);
static void my_exit2 (void);
?
Int
Main (void)
{
? ? if (Atexit (my_exit2)! = 0)
???? . Err_sys ("can ' t register my_exit2");
?
? ? if (Atexit (my_exit1)! = 0)
???? . Err_sys ("can ' t register my_exit1");
? ? if (Atexit (my_exit1)! = 0)
???? . Err_sys ("can ' t register my_exit1");
?
?? printf ("main is done\ n");
? ? return (0);
}
?
static void
My_exit1 (void)
{
?? printf ("first exit handler\ n");
}
?
static void
My_exit2 (void)
{
?? printf ("second exit handler\ n");
}
? Execution results:
?
3 command-line parameter example:
#include "Apue.h"
?
Int
Main (int argc, char *argv[])
{
? ? int ?? I
?
? ? for (i = 0; i < argc; i++)??? / * echo all command-line args * /
? ? ? ? printf ("argv[%d]: %s\n", I, argv[i]);
? ? Exit (0);
}
Execution Result:
?
?
4 List of environment variables
Each program accepts an environment variable list, which is an array that is pointed to by an array pointer, and the array pointer type is:
extern char **environ;
For example, if an environment variable has 5 strings (a C-style string), as shown in:
5 C program's memory layout
The typical C program's memory layout looks like this:
Description
- Text Segment, which holds the machine instructions the CPU will execute. Text segments are shareable, so when a program executes multiple times, the corresponding text segment needs only one copy in memory. The text segment is read-only (read-only), which prevents the program's instructions from being modified.
- The initialized data segment (initialized data segment), which holds the initialized global variable (defined outside any function) in the program. For example: int maxcount = 99; The global variable variable maxcount is saved in the initialization data segment.
- Uninitialized segments (uninitialized data segment), also known as BSS (block started by symbol), the data in this segment is initialized to 0 or null by the kernel before the program executes.; For example, define a global variable (defined outside any function), long sum[1000];? The variable is saved in the uninitialized data segment.
- Stack: Stores temporary variables, function-related information. When a function is called, the return address, the caller-related information (such as register information) is saved in the stack. The called function allocates a portion of space on the stack to hold its temporary variables. Recursive invocation of functions is also applied to this principle. Each time the function calls itself, the information of the current function is saved, and then a new space is opened on the stack to hold the information of the function, and the previous function has no effect.
- Heap: Dynamic memory allocation location. The location of the heap is in the middle of the uninitialized data segment and stack.
?
6 memory allocation (Allocation)
There are three functions available for memory allocation:
- malloc: Allocates memory for the specified number of bytes, uninitialized.
- Calloc: Allocates memory for a specified number of object sizes, and memory is initialized to 0;
- ReAlloc: Increases or decreases the previously allocated memory. Move the contents of the old memory to the new larger memory block, and the extra portion of the memory is uninitialized.
function declaration:
#include <stdlib.h>
void *malloc (size_t size);
void *calloc (size_t nobj, size_t size);
void *realloc (void *ptr, size_t newsize);
void free (void* ptr);
Function Details:
- The memory pointers returned by three functions must be memory-aligned so that they can be used to store different objects;
- The free function frees the memory that the PTR points to, and the allocated memory is placed in the memory pool for the next memory allocation;
- The ReAlloc function is used to change the size of previously allocated memory. For example, at runtime we applied for a memory to store 512 elements of the array, and later found that the memory size is not enough, you can call realloc. If the operating system discovers that there is enough memory behind the current memory, it allocates the extra memory directly into the current memory, and then returns the incoming pointer (that is, the direct expansion memory). However, if there is not enough space behind the current memory, the system allocates a large enough amount of memory, copies the contents of the old memory block into the new memory block, and returns the address of the new memory.
- Memory allocation functions are implemented using system call SBRK. The function of the system call is to extend the heap of the process.
- Generally, the actual allocated memory block is larger than the request, the extra part is used to store the memory block size, pointing to the next memory block pointers and other information. The error of writing the overwrite information record area is very covert and serious.
?
7 Environment variables (environment Variable)
The string form of the environment variable:
Name=value
The kernel does not care about environment variables, and the environment variables are used by various applications.
Gets the environment variable value using the function getenv.
#include <stdlib.h>
char* getenv (const char* name);
Returns:pointer to value associated with name, NULL if not found
Functions to modify environment variables:
#include <stdlib.h>
int putenv (char* str);
int setenv (const char* name, const char* value, int rewrite);
int unsetenv (const char* name);
? Function Details:
- The function putenv passes in a string in the form Name=value, which is added to the environment variable list. If name already exists, delete the old definition first.
- The function setenv passes in a name and a value, and if name already exists, the parameter rewrite determines whether the old definition is overwritten, and if rewrite is nonzero, the old definition is overwritten.
- The function unsetenv deletes the definition of name and does not error if name does not exist.
? The process of modifying the list of environment variables is a very interesting thing.
As you can see from the above C program memory layout diagram, the list of environment variables (a set of pointers that hold pointers to environment variable strings) is stored in memory above the stack.
In this memory, it is simple to delete a string. We just need to find the pointer, delete the pointer, and the string that the pointer points to.
However, it is much more difficult to add or modify an environment variable. Because the memory of the environment variable list is often at the top of the memory space of the process, the following is the stack. So the memory space cannot be scaled up or down.
So the process of modifying the list of environment variables is as follows:
- If we modify a name that already exists:
- If the size of the new value is smaller or equivalent than the value already exists, overwrite the old value directly;
- If the new value is larger than the value already exists, then we must make a new memory space for the new value malloc, copy the new value into that memory, and replace the pointer to the old value with a pointer to the new value.
- If we add an environment variable:
- First we need to call malloc to allocate space for the string name=value, copy the string into the target memory;
- If this is the first time we have added an environment variable, we need to call malloc to allocate a new space, copy the old environment volume list into the new memory, and add the target environment variable after the list. We then set environ to point to the new environment variable list.
- If this is not the first time we have added an environment variable, then we just need to realloc allocate more space for an environment variable, the new environment variable is saved at the end of the list, and the list is still a null pointer.
?
Summary
This article describes the process startup and exit, memory layout, environment variable list, and environment variable modification.
The next one will then learn four functions setjmp, longjmp, Getrlimit, and Setrlimit.
?
?
Resources:
"Advanced programming in the UNIX envinronment 3rd"
UNIX Advanced Environment Programming (8) Process environment (process environment)-Start and exit of processes, memory layout, environment variable list