Linux Kernel programming (blocking processes)

Source: Internet
Author: User
Linux Kernel programming (blocking process)-General Linux technology-Linux programming and kernel information. The following is a detailed description. What if someone asks you to do what you cannot do for the moment? If you are an individual disturbed by another person, the only thing you can do is to say to him: "No, I am very busy. Go away !" However, if you are a kernel module and are disturbed by processes, you have another option. You can suspend the process until you can provide services for it. After all, the process is constantly suspended or awakened by the kernel (this is the way multiple processes seem to run on one processor at the same time ).
This kernel module is an example. This file (called/proc/sleep) can only be opened by one process at a time. If the file has been opened, the kernel module calls module_interruptible_sleep_on (note 8.1 ). This function changes the status of a task (a task is a kernel data structure that contains processes and information called by the system) to TASK_INTERRUPTIBLE, indicating that the task will not run until it is awakened, and add it to the WaitQ -- task queue waiting for file access. Then, this function calls the scheduler to switch context to other processes that require CPU usage.
After the process completes File Processing, close the file and call module _ close. This function wakes up all processes in the queue (there is no mechanism to wake up one of them ). Then, the process that closes the file can continue to run. The scheduler promptly determines which process has been completed and controls the CPU to another process. At the same time, a process in the queue will get CPU control from the scheduler. It is starting after calling module_interruptible_sleep_on. Then it can set a global variable to tell other processes that the file is still open and its life is continuing. When other processes have the opportunity to obtain the CPU, they will see this global variable and then suspend it again.
In order to make life more exciting, module_close does not monopolize the process of waking up and waiting for file access. A signal like Ctrl-C (SIGINT) can also wake up the process. In this case, we want to return-EINTR immediately. This is very important. For example, you can kill a process before the process receives a file.
Remember another point. Sometimes processes do not want to be suspended, they want to get what they want immediately, or they are told that they cannot do it. Such a process uses the O_NONBLOCK flag when opening a file. The kernel returns an ERROR code-ERROR in response to other pending operations (such as opening a file in this example. The program cat_noblock can be used to open the file using the O_NONBLOCK flag, which can be found in the source program directory in this chapter.
Ex sleep. c

/* Sleep. c-create a/proc file, and if several
* Processes try to open it at the same time, put all
* But one to sleep */


/* Copyright (C) 1998-99 by Ori Pomerantz */


/* The necessary header files */

/* Standard in kernel modules */
# Include/* Were doing kernel work */
# Include/* Specifically, a module */

/* Deal with CONFIG_MODVERSIONS */
# If CONFIG_MODVERSIONS = 1
# Define MODVERSIONS
# Include
# Endif

/* Necessary because we use proc fs */
# Include

/* For putting processes to sleep and waking them up */
# Include
# Include



/* In 2.2.3/usr/include/linux/version. h between des
* Macro for this, but 2.0.35 doesnt-so I add it
* Here if necessary .*/
# Ifndef KERNEL_VERSION
# Define KERNEL_VERSION (a, B, c) (a) x 65536 + (B) * 256 + (c ))
# Endif


# If LINUX_VERSION_CODE> = KERNEL_VERSION (2, 2, 0)
# Include/* for get_user and put_user */
# Endif


/* The modules file functions ***********************/


/* Here we keep the last message sent Ed, to prove
* That we can process our input */
# Define MESSAGE_LENGTH 80
Static char Message [MESSAGE_LENGTH];


/* Since we use the file operations struct, we cant use
* The special proc output provisions-we have to use
* A standard read function, which is this function */
# If LINUX_VERSION_CODE> = KERNEL_VERSION (2, 2, 0)
Static ssize_t module_output (
Struct file * file,/* The file read */
Char * buf,/* The buffer to put data to (in
* User segment )*/
Size_t len,/* The length of the buffer */
Loff_t * offset)/* Offset in the file-ignore */
# Else
Static int module_output (
Struct inode * inode,/* The inode read */
Struct file * file,/* The file read */
Char * buf,/* The buffer to put data to (in
* User segment )*/
Int len)/* The length of the buffer */
# Endif
{
Static int finished = 0;
Int I;
Char message [MESSAGE_LENGTH + 30];

/* Return 0 to signify end of file-that we have
* Nothing more to say at this point .*/
If (finished ){
Finished = 0;
Return 0;
}

/* If you dont understand this by now, youre
* Hopeless as a kernel programmer .*/
Sprintf (message, "Last input: % s \ n", Message );
For (I = 0; I
Put_user (message , Buf + I );

Finished = 1;
Return I;/* Return the number of bytes "read "*/
}


/* This function starts es input from the user when
* The user writes to the/proc file .*/
# If LINUX_VERSION_CODE> = KERNEL_VERSION (2, 2, 0)
Static ssize_t module_input (
Struct file * file,/* The file itself */
Const char * buf,/* The buffer with input */
Size_t length,/* The buffers length */
Loff_t * offset)/* offset to file-ignore */
# Else
Static int module_input (
Struct inode * inode,/* The files inode */
Struct file * file,/* The file itself */
Const char * buf,/* The buffer with the input */
Int length)/* The buffers length */
# Endif
{
Int I;

/* Put the input into Message, where module_output
* Will later be able to use it */
For (I = 0; I
# If LINUX_VERSION_CODE> = KERNEL_VERSION (2, 2, 0)
Get_user (Message, Buf + I );
# Else
Message= Get_user (buf + I );
# Endif
/* We want a standard, zero terminated string */
Message= \;

/* We need to return the number of input
* Characters used */
Return I;
}

/* 1 if the file is currently open by somebody */
Int Already_Open = 0;

/* Queue of processes who want our file */
Static struct wait_queue * WaitQ = NULL;


/* Called when the/proc file is opened */
Static int module_open (struct inode * inode,
Struct file * file)
{
/* If the files flags include O_NONBLOCK, it means
* The process doesnt want to wait for the file.
* In this case, if the file is already open, we
* Shocould fail with-EAGAIN, meaning "youll have
* Try again ", instead of blocking a process which
* Wocould rather stay awake .*/
If (file-> f_flags & O_NONBLOCK) & Already_Open)
Return-EAGAIN;

/* This is the correct place for MOD_INC_USE_COUNT
* Because if a process is in the loop, which is
* Within the kernel module, the kernel module must
* Not be removed .*/
MOD_INC_USE_COUNT;

/* If the file is already open, wait until it isnt */
While (Already_Open)
{
# If LINUX_VERSION_CODE> = KERNEL_VERSION (2, 2, 0)
Int I, is_sig = 0;
# Endif

/* This function puts the current process,
* Including any system CILS, such as us, to sleep.
* Execution will be resumed right after the function
* Call, either because somebody called
* Wake_up (& WaitQ) (only module_close does that,
* When the file is closed) or when a signal, such
* As Ctrl-C, is sent to the process */
Module_interruptible_sleep_on (& WaitQ );

/* If we woke up because we got a signal were not
* Blocking, return-EINTR (fail the system call ).
* This allows processes to be killed or stopped .*/



/*
* Emmanuel Papirakis:
*
* This is a little update to work with 2. 2. *. Signals
* Now are contained in two words (64 bits) and are
* Stored in a structure that contains an array of two
* Unsigned longs. We now have to make 2 checks in our if.
*
* Ori Pomerantz:
*
* Nobody promised me theyll never use more than 64
* Bits, or that this book wont be used for a version
* Of Linux with a word size of 16 bits. This code
* Wocould work in any case.
*/
# If LINUX_VERSION_CODE> = KERNEL_VERSION (2, 2, 0)

For (I = 0; I <_ NSIG_WORDS &&! Is_sig; I ++)
Is_sig = current-> signal. sig&
~ Current-> blocked. sig;
If (is_sig ){
# Else
If (current-> signal &~ Current-> blocked ){
# Endif
/* Its important to put MOD_DEC_USE_COUNT here,
* Because for processes where the open is
* Interrupted there will never be a corresponding
* Close. If we dont decrement the usage count
* Here, we will be left with a positive usage
* Count which well have no way to bring down
* Zero, giving us an immortal module, which can
* Only be killed by rebooting the machine .*/
MOD_DEC_USE_COUNT;
Return-EINTR;
}
}

/* If we got here, Already_Open must be zero */

/* Open the file */
Already_Open = 1;
Return 0;/* Allow the access */
}



/* Called when the/proc file is closed */
# If LINUX_VERSION_CODE> = KERNEL_VERSION (2, 2, 0)
Int module_close (struct inode * inode, struct file * file)
# Else
Void module_close (struct inode * inode, struct file * file)
# Endif
{
/* Set Already_Open to zero, so one of the processes
* In the WaitQ will be able to set Already_Open back
* To one and to open the file. All the other processes
* Will be called when Already_Open is back to one, so
* Theyll go back to sleep .*/
Already_Open = 0;

/* Wake up all the processes in WaitQ, so if anybody
* Is waiting for the file, they can have it .*/
Module_wake_up (& WaitQ );

MOD_DEC_USE_COUNT;

# If LINUX_VERSION_CODE> = KERNEL_VERSION (2, 2, 0)
Return 0;/* success */
# Endif
}




/* This function decides whether to allow an operation
* (Return zero) or not allow it (return a non-zero
* Which indicates why it is not allowed ).
*
* The operation can be one of the following values:
* 0-Execute (run the "file"-meaningless in our case)
* 2-Write (input to the kernel module)
* 4-Read (output from the kernel module)
*
* This is the real function that checks file
* Permissions. The permissions returned by ls-l are
* For referece only, and can be overridden here.
*/
Static int module_permission (struct inode * inode, int op)
{
/* We allow everybody to read from our module,
* Only root (uid 0) may write to it */
If (op = 4 | (op = 2 & current-> euid = 0 ))
Return 0;

/* If its anything else, access is denied */
Return-EACCES;
}


/* Structures to register as the/proc file,
* Pointers to all the relevant functions .************/


/* File operations for our proc file. This is where
* We place pointers to all the functions called when
* Somebody tries to do something to our file. NULL
* Means we dont want to deal with something .*/
Static struct file_operations File_Ops_4_Our_Proc_File =
{
NULL,/* lseek */
Module_output,/* "read" from the file */
Module_input,/* "write" to the file */
NULL,/* readdir */
NULL,/* select */
NULL,/* ioctl */
NULL,/* mmap */
Module_open,/* called when the/proc file is opened */
# If LINUX_VERSION_CODE> = KERNEL_VERSION (2, 2, 0)
NULL,/* flush */
# Endif
Module_close/* called when its classed */
};



/* Inode operations for our proc file. We need it so
* Well have somewhere to specify the file operations
* Structure we want to use, and the function we use
* Permissions. Its also possible to specify functions
* To be called for anything else which cocould be done to
* Inode (although we dont bother, we just put NULL ).*/
Static struct inode_operations Inode_Ops_4_Our_Proc_File =
{
& File_Ops_4_Our_Proc_File,
NULL,/* create */
NULL,/* lookup */
NULL,/* link */
NULL,/* unlink */
NULL,/* symlink */
NULL,/* mkdir */
NULL,/* rmdir */
NULL,/* mknod */
NULL,/* rename */
NULL,/* readlink */
NULL,/* follow_link */
NULL,/* readpage */
NULL,/* writepage */
NULL,/* bmap */
NULL,/* truncate */
Module_permission/* check for permissions */
};

/* Directory entry */
Static struct proc_dir_entry Our_Proc_File =
{
0,/* Inode number-ignore, it will be filled
* Proc_register [_ dynamic] */
5,/* Length of the file name */
"Sleep",/* The file name */
S_IFREG | S_IRUGO | S_IWUSR,
/* File mode-this is a regular file which
* Can be read by its owner, its group, and everybody
* Else. Also, its owner can write to it.
*
* Actually, this field is just for reference, its
* Module_permission that does the actual check. It
* Cocould use this field, but in our implementation it
* Doesnt, for simplicity .*/
1,/* Number of links (directories where
* File is referenced )*/
0, 0,/* The uid and gid for the file-we give
* It to root */
80,/* The size of the file reported by ls .*/
& Inode_Ops_4_Our_Proc_File,
/* A pointer to the inode structure
* The file, if we need it. In our case we
* Do, because we need a write function .*/
NULL/* The read function for the file.
* Irrelevant, because we put it
* In the inode structure above */
};



/* Module initialization and cleanup *****************/


/* Initialize the module-register the proc file */
Int init_module ()
{
/* Success if proc_register_dynamic is a success,
* Failure otherwise */
# If LINUX_VERSION_CODE> = KERNEL_VERSION (2, 2, 0)
Return proc_register (& proc_root, & Our_Proc_File );
# Else
Return proc_register_dynamic (& proc_root, & Our_Proc_File );
# Endif

/* Proc_root is the root directory for the proc
* Fs (/proc). This is where we want our file to be
* Located.
*/
}


/* Cleanup-unregister our file from/proc. This cocould
* Get dangerous if there are still processes waiting in
* WaitQ, because they are inside our open function,
* Which will get unloaded. Ill explain how to avoid
* Removal of a kernel module in such a case in
* Chapter 10 .*/
Void cleanup_module ()
{
Proc_unregister (& proc_root, Our_Proc_File.low_ino );
}
Related Article

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.