Single-instance Implementation of daemon _ not peaceful _ Baidu Space

Source: Internet
Author: User

Single-instance Implementation of daemon _ not peaceful _ Baidu Space

Single-instance Implementation of daemon

To work properly, the daemon should be implemented as a single instance, that is, to run only one copy of the daemon at any time, because the daemon needs to access a device. The file lock mechanism is used here. If the daemon creates a file and adds a lock to the entire file, only one such write lock can be created, after that, if you try to create another write lock, it will fail, so as to indicate to the replica of the daemon process that a copy is already running. This lock file is usually stored in the/var/run directory. The name of the lock file is usually name. PID, where name is the name of the daemon. Note: The daemon may need root permission to create files in this directory.

CodeImplementation and analysis:

 

# Include <stdio. h>
# Include <signal. h>
# Include <syslog. h>
# Include <unistd. h>
# Include <fcntl. h>
# Include <time. h>
# Include <errno. h>
# Include <string. h>
# Include <sys/STAT. h>
# Include <sys/file. h>
# Include <sys/IOCTL. h>
# Include <stdlib. h>

# Define lockfile "/var/run/test. PID"
# Define lockmode (s_irusr | s_iwusr | s_irgrp | s_iroth)

// 0 is returned for success. If an error is returned,-1 is returned. The cause of the error is errno.

Int lockfile (INT ff)
{
Struct flock FL;

// Rochelle type is the locked state. It has three states: f_rdlck is used to create a lock for reading, f_wrlck is used to create a lock for writing, and f_unlck is used to delete a previously created lock.

Fl. l_type = f_wrlck;

// Rochelle start indicates the starting position of the locked area.

Fl. l_start = 0;

// Rochelle whenec determines the Rochelle start position. It has three states: seek_set is the starting position of the file to be locked; seek_cur is the starting position of the current file read/write location as the lock; seek_end is the starting position of the file to be locked at the end.

Fl. l_whence = seek_set;

// L_len is used to set the size of the locked area.

Fl. l_len = 0;
// Another Rochelle PID is used to set the lock action.


// Fcntl () is the only POSIX-compliant file lock implementation, so it is also the only portable and powerful.

// F_setlk: If l_whence, l_start, and l_len are all set, a lock is assigned if l_type is set to f_rdlck or f_wrlck, if l_type is set to f_unlck, a lock is released. If it fails,-1 is returned, and errno error is set to eacces or eagain.

Return (fcntl (FF, f_setlk, & FL ));
}

Void already_running (void)
{
Int FD;
Char Buf [16];

// Here, open is the system call function, and the first parameter is the file path to open; the second parameter is the permission to operate on the file, which is readable and writable, can be created (if the file does not exist, it will be automatically created). The third parameter is the permission granted to the file after the file is created. For example, s_irusr is equivalent to 400, and the user has the read permission.

FD = open (lockfile, o_rdwr | o_creat, lockmode );

If (FD <0)
{
// Strerror (), returns an error of the string type.

Syslog (log_err, "can't open % s: % s", lockfile, strerror (errno ));
Exit (1 );
}

If (lockfile (FD) <0)
{
If (errno = eacces | errno = eagain)
{
Close (FD );
Exit (1 );
}
Syslog (log_err, "can't lock % s: % s", lockfile, strerror (errno ));
Exit (1 );
}
// Change the file size specified by FD to 0. The FD parameter is an opened file description and must be a file opened in write mode. The reason for truncating the file length is 0 because the ID string of the previous process can be longer than the ID string of the current process.

Ftruncate (FD, 0 );

// Convert an integer to a string

Sprintf (BUF, "% d", getpid ());

// Write the process ID converted to a string to the file/var/run/*. PID.

Write (FD, Buf, strlen (BUF ));
}

Int main (INT argc, char * argv [])
{
// Time_t now;

Int childpid, FD, fdtablesize;
// Int error, in, out;

Int FP;

// Shield some signals related to control terminal operations. When the daemon process is not running properly, the control terminal is blocked and exited or suspended. The I/O and stop signals of the terminal are ignored.

Signal (sigttou, sig_ign );
Signal (sigttin, sig_ign );
Signal (sigtstp, sig_ign );
Signal (sighup, sig_ign );

// Because the child process inherits some features of the parent process, such as the control terminal, logon session, and process group, the daemon process must eventually run in the background from the control terminal, therefore, the parent process must be killed to ensure that the child process is not the process leader, which is required to successfully call setsid.

If (Fork ()! = 0)
{
Exit (1 );
}

// The logon session and process group must be detached from the control terminal. You can call the setsid () function to become a new session leader and a new process leader after successful calls, it is also separated from the original logon session and process group. Because the session process is dedicated to the control terminal, the process is also separated from the control terminal.

/*
If (setsid () <0)
{
Exit (1 );
}
*/
// You can use the following processing method to achieve the setsid () function. "/Dev/tty" is a stream device and a terminal ing. Call the close () function to close the terminal.

If (FP = open ("/dev/tty", o_rdwr)> = 0)
{
IOCTL (FP, tiocnotty, null );
Close (FP );
}

// The process has become the no-end session leader, but it can re-apply to open a new control terminal. You can disable the process from re-opening the control terminal by making the process no longer the session leader. You need to call the fork function again.

If (Fork ()! = 0)
{
Exit (1 );
}

// The current working directory inherited from the parent process may be in an assembled file system. Because the daemon usually exists before the system restarts, if the current working directory of the daemon is in an assembly file system, the file system cannot be uninstalled. For example, the current directory inherited from the parent process is a mounted directory under/MNT.

If (chdir ("/tmp") =-1)
{
Exit (1 );
}

// Disable the opened file descriptor or redirect the file descriptor of the standard input, standard output, and standard error output. A process inherits the opened file descriptor from the parent process that created it. If you do not close the service, system resources will be wasted and unexpected errors will occur. Getdtablesize () returns the maximum number of files that a process can open.

For (FD = 0, fdtablesize = getdtablesize (); FD <fdtablesize; FD ++)
{
Close (FD );
}

// SomeProgramSome special requirements also need to be redirected.

/*
Error = open ("/tmp/error", o_wronly | o_creat, 0600 );
Dup2 (error, 2 );
Close (error );
In = open ("/tmp/in", o_rdonly | o_creat, 0600 );
If (dup2 (in, 0) =-1) perror ("in ");
Close (in );
Out = open ("/tmp/out", o_wronly | o_creat, 0600 );
If (dup2 (Out, 1) =-1) perror ("out ");
Close (out );
*/

// Blocking words created by using the inherited file method may refuse to set certain permissions, so you need to grant all permissions again.

Umask (0 );

// If the parent process does not wait for the completion of the Child process, the child process will become a zombie process, occupying system resources. If the parent process waits for the completion of the Child process, it will increase the burden on the parent process, it affects the concurrent performance of server processes. Therefore, the sigchld signal must be processed to recycle the resources of the zombie process to avoid unnecessary waste of resources.

Signal (sigchld, sig_ign );

// The daemon does not belong to any terminal. Therefore, when some information needs to be output, it cannot directly output the information to the terminal as a general program. You can use the syslogd daemon in Linux, it provides users with syslog () System Call functions. Information is stored in the/var/log/syslog file.

Syslog (log_user | log_info, "daemon test! \ N ");

// The information sent by syslog () is written to the/var/log/syslog log file every 60 seconds.

/* While (1)
{
// Time (time_t * t) returns all the seconds from January 1, 1970 00:00:00 to the present.
Time (& now );

// Obtain the parent process ID and child process ID.
Syslog (log_user | log_info, "ppid: % d PID: % d \ n", getppid (), getpid ());

// Ctime (const time_t *) returns a char pointer of the current time.
Syslog (log_user | log_info, "Current Time: % s \ n", ctime (& now ));

// Sleep for 60 seconds
Sleep (60 );
}
*/
While (1)
{
Already_running ();
Sleep (60 );
}
Return 0;
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.