CEF427 Chapter 1: Inter Process Communication PDF

Document Details

SaneNewYork8021

Uploaded by SaneNewYork8021

Université de Buea

Tags

inter-process communication operating systems computer science programming

Summary

This document provides an introduction to Inter-Process Communication (IPC) concepts in operating systems. It covers different types of IPC mechanisms such as pipes, message queues, shared memory along with related system calls. The document mainly focuses on theoretical foundation.

Full Transcript

Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 CEF427: ADVANCED OPERATING SYSTEMS Chapter 1: Introduction to Inter process communication I. Introduction Inter Process Communication (IPC) is a mechanism that involves commun...

Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 CEF427: ADVANCED OPERATING SYSTEMS Chapter 1: Introduction to Inter process communication I. Introduction Inter Process Communication (IPC) is a mechanism that involves communication of one process with another process. This usually occurs only in one system. Communication can be of two types − Between related processes initiating from only one process, such as parent and child processes. Between unrelated processes, or two or more different processes. Following are some important terms that we need to know before proceeding further on this topic. Pipes − Communication between two related processes. The mechanism is half duplex meaning the first process communicates with the second process. To achieve a full duplex i.e., for the second process to communicate with the first process another pipe is required. FIFO − Communication between two unrelated processes. FIFO is a full duplex, meaning the first process can communicate with the second process and vice versa at the same time. Message Queues − Communication between two or more processes with full duplex capacity. The processes will communicate with each other by posting a message and retrieving it out of the queue. Once retrieved, the message is no longer available in the queue. Shared Memory − Communication between two or more processes is achieved through a shared piece of memory among all processes. The shared memory needs to be protected from each other by synchronizing access to all the processes. Semaphores − Semaphores are meant for synchronizing access to multiple processes. When one process wants to access the memory (for reading or writing), it needs to be locked (or protected) and released when the access is removed. This needs to be repeated by all the processes to secure data. Signals − Signal is a mechanism to communication between multiple processes by way of signalling. This means a source process will send a signal (recognized by number) and the destination process will handle it accordingly. Proposed by Dr. SOP DEFFO Lionel L. 1 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 II. Process information Before we go into process information, we need to know a few things, such as : -What is a process? A process is a program in execution. -What is a program? A program is a file containing the information of a process and how to build it during run time. When you start execution of the program, it is loaded into RAM and starts executing. Each process is identified with a unique positive integer called as process ID or simply PID (Process Identification number). The kernel usually limits the process ID to 32767, which is configurable. When the process ID reaches this limit, it is reset again, which is after the system processes range. The unused process IDs from that counter are then assigned to newly created processes. The system call getpid() returns the process ID of the calling process. #include #include pid_t getpid(void); This call returns the process ID of the calling process which is guaranteed to be unique. This call is always successful and thus no return value to indicate an error. Each process has its unique ID called process ID that is fine but who created it? How to get information about its creator? Creator process is called the parent process. Parent ID or PPID can be obtained through getppid() call. The system call getppid() returns the Parent PID of the calling process. #include #include pid_t getppid(void); This call returns the parent process ID of the calling process. This call is always successful and thus no return value to indicate an error. Let us understand this with a simple example. Following is a program to know the PID and PPID of the calling process. File name: processinfo.c #include #include #include #include Proposed by Dr. SOP DEFFO Lionel L. 2 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 int main() { int mypid, myppid; printf("Program to know PID and PPID's information\n"); mypid = getpid(); myppid = getppid(); printf("My process ID is %d\n", mypid); printf("My parent process ID is %d\n", myppid); printf("Cross verification of pid's by executing process commands on shell\n"); system("ps -ef"); return 0; } On compilation and execution of the above program, following will be the output. Proposed by Dr. SOP DEFFO Lionel L. 3 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 Note − The “C” library function system() executes a shell command. The arguments passed to system() are commands executed on shell. In the above program, command is “ps”, which gives process status. The complete information about all running processes and other system related information are accessible from proc file system available at /proc location. III. Process Image Now that we have seen how to get the basic information of process and its parent process, it is time to look into the details of process/program information. What exactly is process image? Process image is an executable file required while executing the program. This image usually contains the following sections − Code segment or text segment Data segment Stack segment Heap segment Following is the pictorial representation of the process image. Proposed by Dr. SOP DEFFO Lionel L. 4 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 Code segment is a portion of object file or program’s virtual address space that consists of executable instructions. This is usually read-only data segment and has a fixed size. Data segment is of two types. Initialized Un-initialized Initialized data segment is a portion of the object file or program’s virtual address space that consists of initialized static and global variables. Un-initialized data segment is a portion of the object file or program’s virtual address space that consists of uninitialized static and global variables. Un-initialized data segment is also called BSS (Block Started by Symbol) segment. Data segment is read-write, since the values of variables could be changed during run time. This segment also has a fixed size. Stack segment is an area of memory allotted for automatic variables and function parameters. It also stores a return address while executing function calls. Stack uses LIFO (Last-In-First-Out) mechanism for storing local or automatic variables, function parameters and storing next address or return address. The return address refers to the address to return after completion of function execution. This segment size is variable as per local variables, function parameters, and function calls. This segment grows from a higher address to a lower address. Heap segment is area of memory allotted for dynamic memory storage such as for malloc() and calloc() calls. This segment size is also variable as per user allocation. This segment grows from a lower address to a higher address. Let us now check how the segments (data and bss segments) size vary with a few sample programs. Segment size is known by executing the command “size”. Initial program File: segment_size1.c #include int main() { printf("Hello World\n"); return 0; } In the following program, an uninitialized static variable is added. This means uninitialized segment (BSS) size would increase by 4 Bytes. Note − In Linux operating system, the size of int is 4 bytes. Size of the integer data type depends on the compiler and operating system support. Proposed by Dr. SOP DEFFO Lionel L. 5 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 File: segment_size2.c #include int main() { static int mystaticint1; printf("Hello World\n"); return 0; } In the following program, an initialized static variable is added. This means initialized segment (DATA) size would increase by 4 Bytes. File: segment_size3.c #include int main() { static int mystaticint1; static int mystaticint2 = 100; printf("Hello World\n"); return 0; } In the following program, an initialized global variable is added. This means initialized segment (DATA) size would increase by 4 Bytes. File: segment_size4.c #include int myglobalint1 = 500; int main() { static int mystaticint1; static int mystaticint2 = 100; printf("Hello World\n"); return 0; } In the following program, an uninitialized global variable is added. This means uninitialized segment (BSS) size would increase by 4 Bytes. File: segment_size5.c #include int myglobalint1 = 500; int myglobalint2; int main() { Proposed by Dr. SOP DEFFO Lionel L. 6 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 static int mystaticint1; static int mystaticint2 = 100; printf("Hello World\n"); return 0; } Execution Steps Compilation Lionel $ gcc segment_size1.c -o segment_size1 Lionel $ gcc segment_size2.c -o segment_size2 Lionel $ gcc segment_size3.c -o segment_size3 Lionel $ gcc segment_size4.c -o segment_size4 Lionel $ gcc segment_size5.c -o segment_size5 Execution/Output Lionel size segment_size1 segment_size2 segment_size3 segment_size4 segment_size5 text data bss dec hex filename 878 252 8 1138 472 segment_size1 878 252 12 1142 476 segment_size2 878 256 12 1146 47a segment_size3 878 260 12 1150 47e segment_size4 878 260 16 1154 482 segment_size5 Lionel IV. Process Creation and Termination Till now we know that whenever we execute a program then a process is created and would be terminated after the completion of the execution. What if we need to create a process within the program and may be wanted to schedule a different task for it. Can this be achieved? Yes, obviously through process creation. Of course, after the job is done it would get terminated automatically or you can terminate it as needed. Process creation is achieved through the fork() system call. The newly created process is called the child process and the process that initiated it (or the process when execution is started) is called the parent process. After the fork() system call, now we have two processes - parent and child processes. How to differentiate them? Very simple, it is through their return values. Proposed by Dr. SOP DEFFO Lionel L. 7 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 After creation of the child process, let us see the fork() system call details. #include #include pid_t fork(void); Creates the child process. After this call, there are two processes, the existing one is called the parent process and the newly created one is called the child process. The fork() system call returns either of the three values − Negative value to indicate an error, i.e., unsuccessful in creating the child process. Returns a zero for child process. Returns a positive value for the parent process. This value is the process ID of the newly created child process. Let us consider a simple program. File name: basicfork.c #include #include #include int main() { fork(); printf("Called fork() system call\n"); return 0; } Execution Steps Compilation gcc basicfork.c -o basicfork Execution/Output Called fork() system call Called fork() system call Note − Usually after fork() call, the child process and the parent process would perform different tasks. If the same task needs to be run, then for each fork() call it would run 2 power n times, where n is the number of times fork() is invoked. Proposed by Dr. SOP DEFFO Lionel L. 8 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 In the above case, fork() is called once, hence the output is printed twice (2 power 1). If fork() is called, say 3 times, then the output would be printed 8 times (2 power 3). If it is called 5 times, then it prints 32 times and so on and so forth. Having seen fork() create the child process, it is time to see the details of the parent and the child processes. File name: pids_after_fork.c #include #include #include int main() { pid_t pid, mypid, myppid; pid = getpid(); printf("Before fork: Process id is %d\n", pid); pid = fork(); if (pid < 0) { perror("fork() failure\n"); return 1; } // Child process if (pid == 0) { printf("This is child process\n"); mypid = getpid(); myppid = getppid(); printf("Process id is %d and PPID is %d\n", mypid, myppid); } else { // Parent process sleep(2); printf("This is parent process\n"); mypid = getpid(); myppid = getppid(); printf("Process id is %d and PPID is %d\n", mypid, myppid); printf("Newly created process id or child pid is %d\n", pid); } return 0; } Compilation and Execution Steps Before fork: Process id is 166629 This is child process Process id is 166630 and PPID is 166629 Before fork: Process id is 166629 This is parent process Process id is 166629 and PPID is 166628 Proposed by Dr. SOP DEFFO Lionel L. 9 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 Newly created process id or child pid is 166630 A process can terminate in either of the two ways − Abnormally, occurs on delivery of certain signals, say terminate signal. Normally, using _exit() system call (or _Exit() system call) or exit() library function. The difference between _exit() and exit() is mainly the cleanup activity. The exit() does some cleanup before returning the control back to the kernel, while the _exit() (or _Exit()) would return the control back to the kernel immediately. Consider the following example program with exit(). File name: atexit_sample.c #include #include void exitfunc() { printf("Called cleanup function - exitfunc()\n"); return; } int main() { atexit(exitfunc); printf("Hello, World!\n"); exit (0); } Note : In the C Programming Language, the atexit function registers a function as a termination function which is called if the program terminates normally. When calling the atexit function more than once, the last function to be registered is the first function that will be called when the program is terminated normally. Syntax The syntax for the atexit function in the C Language is: int atexit(void (*func)(void)); Parameters or Arguments func The function to register as a termination function. Returns The atexit function returns zero if successful and a nonzero value if unsuccessful Proposed by Dr. SOP DEFFO Lionel L. 10 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 Compilation and Execution Steps Hello, World! Called cleanup function - exitfunc() Consider the following example program with _exit(). File name: at_exit_sample.c #include #include void exitfunc() { printf("Called cleanup function - exitfunc()\n"); return; } int main() { atexit(exitfunc); printf("Hello, World!\n"); _exit (0); } Compilation and Execution Steps Hello, World! V. Child process monitoring As we have seen, whenever we create a child process from a program using fork, the following happens − Current process now becomes the parent process The new process becomes the child process What happens if the parent process finishes its task early than the child process and then quits or exits? Now who would be the parent of the child process? The parent of the child process is init process, which is the very first process initiating all the tasks. To monitor the child process execution state, to check whether the child process is running or stopped or to check the execution status, etc. the wait() system calls and its variants is used. Let us consider an example program, where the parent process does not wait for the child process, which results into init process becoming the new parent for the child process #include int main() { Proposed by Dr. SOP DEFFO Lionel L. 11 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 int pid; pid = fork(); // Child process if (pid == 0) { system("ps -ef"); sleep(10); system("ps -ef"); } else { sleep(3); } return 0; } Following are the variants of system calls to monitor the child process/es − wait() waitpid() waitid() The wait() system call would wait for one of the children to terminate and return its termination status in the buffer as explained below. #include #include pid_t wait(int *status); This call returns the process ID of the terminated child on success and -1 on failure. The wait() system call suspends the execution of the current process and waits indefinitely until one of its children terminates. The termination status from the child is available in status. Let us modify the previous program, so that the parent process now waits for the child process. #include int main() { int pid; int status; pid = fork(); // Child process if (pid == 0) { system("ps -ef"); sleep(10); system("ps -ef"); return 3; //exit status is 3 from child process Proposed by Dr. SOP DEFFO Lionel L. 12 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 } else { sleep(3); wait(&status); printf("In parent process: exit status from child is decimal %d, hexa %0x\n", status, status); } return 0; } The wait() system call has limitation such as it can only wait until the exit of the next child. If we need to wait for a specific child it is not possible using wait(), however, it is possible using waitpid() system call. The waitpid() system call would wait for specified children to terminate and return its termination status in the buffer as explained below. #include #include pid_t waitpid(pid_t pid, int *status, int options); The above call returns the process ID of the terminated child on success and -1 on failure. The waitpid() system call suspends the execution of the current process and waits indefinitely until the specified children (as per pid value) terminates. The termination status from the child is available in the status. The value of pid can be either of the following − < -1 − Wait for any child process whose process group ID is equal to the absolute value of pid. -1 − Wait for any child process, which equals to that of wait() system call. 0 − Wait for any child process whose process group ID is equal to that of the calling process. >0 − Wait for any child process whose process ID is equal to the value of pid. By default, waitpid() system call waits only for the terminated children but this default behavior can be modified using the options argument. Now let us consider a program as an example, waiting for a specific process with its process id. #include #include #include #include Proposed by Dr. SOP DEFFO Lionel L. 13 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 int main() { int pid; int pids; int status; int numprocesses = 0; int total_processes = 3; while (numprocesses < total_processes) { pid = fork(); // Child process if (pid == 0) { printf("In child process: process id is %d\n", getpid()); sleep(5); return 4; } else { pids[numprocesses] = pid; numprocesses++; printf("In parent process: created process number: %d\n", pid); } } // Waiting for 3rd child process waitpid(pids[total_processes - 1], &status, 0); if (WIFEXITED(status) != 0) { printf("process %d exited normally\n", pids[total_processes - 1]); printf("exit status from child is %d\n", WEXITSTATUS(status)); } else { printf("process %d not exited normally\n", pids[total_processes - 1]); } return 0; } After compilation and execution, following is the output. Proposed by Dr. SOP DEFFO Lionel L. 14 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 Now, let us check for waitid() system call. This system call waits for the child process to change state. #include int waitpid(idtype_t idtype, id_t id, siginfo_t *infop, int options); The above system call waits for the child process to change the state and this call suspends the current/calling process until any of its child process changes its state. The argument ‘infop’ is to record the current state of the child. This call returns immediately, if the process has already changed its state. The value of idtype can be either of the following − P_PID − Wait for any child process whose process ID is equal to that of id. P_PGID − Wait for any child process, whose process group ID is equal to that of id. P_ALL − Wait for any child process and id is ignored. The options argument is to specify which state changes and this can be formed with bitwise OR operation with the below-mentioned flags − WCONTINUED − Returns the status of any child that was stopped and has been continued. WEXITED − Waits for the process to exit. WNOHANG − Returns immediately. WSTOPPED − Waits for the process of any child that has stopped, upon receipt of the signal and returns the status. This call returns 0, if it returns due to a change of the state of one of its children and WNOHANG is used. It returns –1, in case of error and sets the appropriate error number. #include #include #include #include int main() { int pid; int pids; int status; int numprocesses = 0; int total_processes = 3; siginfo_t siginfo; while (numprocesses < total_processes) { Proposed by Dr. SOP DEFFO Lionel L. 15 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 pid = fork(); // Child process if (pid == 0) { printf("In child process: process id is %d\n", getpid()); sleep(5); return 2; } else { pids[numprocesses] = pid; numprocesses++; printf("In parent process: created process number: %d\n", pid); } } // Waiting for 3rd child process status = waitid(P_PID, pids[total_processes - 1], &siginfo, WEXITED); if (status == -1) { perror("waitid error"); return 1; } printf("Info received from waitid is: "); printf("PID of child: %d, real user id of child: %d\n", siginfo.si_pid, siginfo.si_uid); return 0; } After execution and compilation of the above program, following is the result. VI. Process groups, sessions and job control In this section, we will get familiar with Process Groups, Sessions and Job Control. Process Group − Process group is a collection of one or more processes. A process group constitutes of one or more processes sharing the same process group identifier (PGID). A process group ID (PGID) is of the same type (pid_t) as the process ID. A process group has a process group leader, which is the process that creates the group and whose process ID becomes the process group ID of the group. Proposed by Dr. SOP DEFFO Lionel L. 16 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 Sessions − It is a collection of various process groups. Job Control − This permits a shell user to simultaneously execute multiple commands (or jobs), one in the foreground and all remaining in the background. It is also possible to move the jobs from the foreground to the background and vice-versa. Let us understand this with the help of example program/s using shell (BASH). Shell script (in BASH) to perform basic commands (date, echo, sleep and cal) named basic_commands.sh Shell script (in BASH) to perform basic commands (ps, echo) #!/bin/bash #basic_commands.sh date echo "Now sleeping for 10 seconds, so that testing job control functionality is smooth" sleep 10 cal #!/bin/bash #process_status.sh ps echo "Now sleeping for 20 seconds, so that testing job control functionality is smooth" sleep 20 ps Use chmod command to give the file the execute permissions. By default, the normal file would get only read and write permissions and not execute permissions. To stop the current running process, you need to enter CTRL+Z. This gives you a job number. The job can be resumed either in the foreground or the background. If needed, to resume the job in the foreground use ‘fg’ command. If needed, to resume the job in the background, use ‘bg’ command. By using this, it would run only the last stopped process. What if you want to start other than the last stopped process? Just use the job number after fg or bg (say bg %2 or bg %3, etc). If the running job is in the background, you can run any other tasks in the foreground. To get the list of jobs, use command, jobs. It is also possible to terminate the process either with CTRL+C or kill command. You can pass the job number while using the kill command. Check the following output which demonstrates stopping the jobs, moving the jobs from the foreground to the background and vice versa, terminating the jobs, etc Proposed by Dr. SOP DEFFO Lionel L. 17 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 VII. Process ressources The process needs certain resources such as CPU and memory to perform the tasks. Now we will look into the related commands and system calls to know the information on resource utilization and monitoring. Also there are certain limits by default for each process on the resources, and if required the limits can be enhanced to accommodate the application requirements. Following are the essential system or process resources information using commands − The top command $ top The top command continuously displays the usage of system resources. If any process puts the system in some kind of hang state (consuming more of CPU or Memory) it is possible to note the process information and take appropriate action (such as killing the related process). The ps command $ ps The ps command provides information about all the running processes. This helps to monitor and control the processes. Proposed by Dr. SOP DEFFO Lionel L. 18 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 The vmstat command $ vmstat The vmstat command reports the statistics of virtual memory subsystem. It reports the information of processes (waiting to run, sleeping, runnable processes, etc.), memory (virtual memory information such as free, used, etc.), swap area, IO devices, system information (number of interrupts, context switches) and CPU (user, system and idle time). The lsof command $ lsof The lsof command prints the list of open files of all the current running processes, including system processes. The getconf command $ getconf –a The getconf command displays the system configuration variables information. Now, let us take a look at the related system calls. System call getrusage(), which provides information on system resource usage. System calls related to accessing and setting resource limits viz., getrlimit(), setrlimit(), prlimit(). System Resource Usage Call #include #include int getrusage(int who, struct rusage *usage); The system call getrusage() returns the information on the system resource usage. This can include information on self, children, or calling thread using flags RUSAGE_SELF, RUSAGE_CHILDREN, RUSAGE_THREAD for the “who” variable. After the call, it returns the information in the structure rusage. This call would return “0” on success and “-1” on failure. Let us look at the following sample program. #include #include #include Proposed by Dr. SOP DEFFO Lionel L. 19 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 void main(void) { struct rusage res_usage; int retval; retval = getrusage(RUSAGE_SELF, &res_usage); if (retval == -1) { perror("getrusage error"); return; } printf("Details of getrusage:\n"); printf("User CPU time (seconds) is %d\n", (int)res_usage.ru_utime.tv_sec); printf("User CPU time (micro seconds) is %d\n", (int)res_usage.ru_utime.tv_usec); printf("Maximum size of resident set (kb) is %ld\n", res_usage.ru_maxrss); printf("Soft page faults (I/O not required) is %ld\n", res_usage.ru_minflt); printf("Hard page faults (I/O not required) is %ld\n", res_usage.ru_majflt); printf("Block input operations via file system is %ld\n", res_usage.ru_inblock); printf("Block output operations via file system is %ld\n", res_usage.ru_oublock); printf("Voluntary context switches are %ld\n", res_usage.ru_nvcsw); printf("Involuntary context switches are %ld\n", res_usage.ru_nivcsw); return; } Let us now look at the system calls related to accessing and setting resource limits. #include #include int getrlimit(int resource, struct rlimit *rlim); int setrlimit(int resource, const struct rlimit *rlim); int prlimit(pid_t pid, int resource, const struct rlimit *new_limit, struct rlimit *old_limit); The system call getrlimit() gets the resource limits in structure rlimit by inputting the resource one needs such as RLIMIT_NOFILE, RLIMIT_NPROC, RLIMIT_STACK, etc. The system call setrlimit() sets the resource limits as mentioned in the rlimit structure as far as within the limits. Proposed by Dr. SOP DEFFO Lionel L. 20 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 The system call prlimit() is used for varius purposes, such as either for retrieving the current resource limits or for updating the resource limits to new values. The structure rlimit contains two values − Soft limit − Current limit Hard limit − Maximum limit to which it can be extended. RLIMIT_NOFILE − Returns the maximum number of file descriptors that can be opened by this process. For example, if it returns 1024, then the process has file descriptors from 0 to 1023. RLIMIT_NPROC − Maximum number of processes that can be created for a user of that process. RLIMIT_STACK − The maximum size in bytes of the stack segment for that process. All these calls would return “0” on success and “-1” on failure. Let us consider the following example where we are using getrlimit() system call. #include #include #include void main(void) { struct rlimit res_limit; int retval; int resources[] = {RLIMIT_NOFILE, RLIMIT_NPROC, RLIMIT_STACK}; int max_res; int counter = 0; printf("Details of resource limits for NOFILE, NPROC, STACK are as follows: \n"); max_res = sizeof(resources)/sizeof(int); while (counter < max_res) { retval = getrlimit(resources[counter], &res_limit); if (retval == -1) { perror("getrlimit error"); return; } printf("Soft Limit is %ld\n", res_limit.rlim_cur); printf("Hard Limit (ceiling) is %ld\n", res_limit.rlim_max); counter++; } return; } Proposed by Dr. SOP DEFFO Lionel L. 21 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 Let us consider another example with getrlimit() system call but now with prlimit() system call. #include #include #include #include void main(void) { struct rlimit res_limit; int retval; int resources[] = {RLIMIT_NOFILE, RLIMIT_NPROC, RLIMIT_STACK}; int max_res; int counter = 0; printf("Details of resource limits for NOFILE, NPROC, STACK using prlimit are as follows: \n"); max_res = sizeof(resources)/sizeof(int); while (counter < max_res) { retval = prlimit(getpid(), resources[counter], NULL, &res_limit); if (retval == -1) { perror("prlimit error"); return; } printf("Soft Limit is %ld\n", res_limit.rlim_cur); printf("Hard Limit (ceiling) is %ld\n", res_limit.rlim_max); counter++; } return; } Proposed by Dr. SOP DEFFO Lionel L. 22 Faculty of Engineering and technologies / computer engineering/ school year 2024-2025 Proposed by Dr. SOP DEFFO Lionel L. 23

Use Quizgecko on...
Browser
Browser