UNIX Process

49
Introduction to Network Programming in UNIX & LINUX 2-1 © D.Zinchin [[email protected]] UNIX Process Process is any program which is executed by computer’s operation system. Kernel is Operation System, that interacts with hardware and provides services like Memory Management, CPU scheduling, Filesystem, I/O Device access, etc. System Call is direct entry point, provided by Kernel, through which active Process can obtain the service Process Representation in Memory Text Initialized Read-Only Data Initialized Read-Write Data Uninitialized Data Heap Stack Kernel Data read from program file when program is executed User Context Kernel Context Text Actual machine instructions to be executed by hardware Data Program’s data, declared during program start Heap Data space, dynamically allocated by the Process Stack Dynamically allocated Stack Frames, containing return address linkage and data elements for each function call

description

UNIX Process. Process is any program which is executed by computer’s operation system. Kernel is Operation System, that interacts with hardware and provides services like Memory Management, CPU scheduling, Filesystem, I/O Device access, etc. System Call - PowerPoint PPT Presentation

Transcript of UNIX Process

Page 1: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-1© D.Zinchin [[email protected]]

UNIX ProcessProcess

is any program which is executed by computer’s operation system.

Kernel is Operation System, that interacts with hardware and provides services like Memory Management, CPU scheduling, Filesystem, I/O Device access, etc.

System Callis direct entry point, provided by Kernel, through which active Process can obtain the service

Process Representation in Memory

Text

Initialized Read-Only Data

Initialized Read-Write Data

Uninitialized Data

Heap

Stack Kernel Data

read from program file when program is executed

User Context Kernel Context

Text

Actual machine instructions to be executed by hardware

Data

Program’s data, declared during program start

Heap

Data space, dynamically allocated by the Process

Stack

Dynamically allocated Stack Frames, containing return address linkage and data elements for each function call

Page 2: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-2© D.Zinchin [[email protected]]

• Process ID

• Parent Process ID

• Real User ID (RUID = UID of user, who launched the program)

• Real Group ID (RGID = GID of user, who launched the program)

• Saved User ID (SUID = UID of program file owner)

• Saved Group ID (SGID = GID of program file owner)

• Effective User ID (EUID = SUID if ‘Set user ID on execution’ bit is set

= RUID else)

• Effective Group ID (EGID = SGID if ‘Set group ID on execution’ bit is set

= RGID else)

• Process Group ID (PGID = PID of session leader process)

• Terminal Group ID

• Root Directory

• Current Working Directory

• Initial Argument Vector

• Initial Environment Vector

• Signal Handling Settings

• File Mode Creation Mask

• List of open File Descriptors

• Time left until scheduled alarm signal

Process Attributes

File Access Mode Word

Octal Value Meaning

r w x r w

x r w x

s s tls -l

Page 3: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-3© D.Zinchin [[email protected]]

Fork System Call

•The fork() system call creates the copy of process that is executing.• It is an only way in which a new process is created in UNIX.• Returns: child PID >0 - for Parent process,

0 - for Child process,

-1 - in case of error (errno indicates the error).• Fork reasons:

-Make a copy of itself to do another task simultaneously-Execute another program (See exec system call)

pid_t childPID; /* typedef int pid_t */…childPID = fork();

if (childPID < 0){ perror(“fork failed”); exit(1);}else if (childPID > 0) /* This is Parent */{ /* Parent processing */ … exit(0);}else /* childPID == 0 */ /* This is Child */{ /* Child processing */ … exit(0);}

parentfork

Child Process has Shared Text and Copied Data.

It differs from Parent Process by following attributes:• PID (new)• Parent PID (= PID of Parent Process)• Own copies of Parent file descriptors• Time left until alarm signal reset to 0

#include <unistd.h> pid_t fork ();

child

Text …childPID = fork();

Data

Stack

HeapData

Stack

Heap

0PID2

Parent:PID1 Child:PID2

po

inte

r to

Tex

t

po

inte

r to

Tex

t

Page 4: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-4© D.Zinchin [[email protected]]

Exit and Wait System Calls

PPID of Child is set to 1,INIT process will call WAIT.

PPID of Child is set to 1Terminated, WAIT was not called

Child becomes Zombie, Child remains in Process Table until WAIT will be called

------------Running, WAIT is not called yet

Parent accepts Child’s PID and termination status immediately.Child is deleted from Process Table.

Parent blocks waiting for Child Termination

Running, calls WAIT

TerminatedRunningCHILDPARENT

Wait System Call

Exit System Call

#include <stdlib.h>void exit (int status);

• Terminates process execution.• Exit status is passed to the Kernel and then available to the Parent Process (with wait() call)• Only low-order 1 byte used to specify the exit status (0 - success, 1-255 – error)

#include <sys/wait.h>pid_t wait (int *p_status);

• Waits for one of the children process to finish.• Returns: child PID > 0 - PID of child process terminated with exit system call or with signal, -1 - if there aren’t child processes or if wait interrupted with signal (errno=EINTR).• If p_status is not NULL, the 2 low-order bytes will be filled with process status information

Child process terminated with exit(), but yet not wait()-ed by Parent process, becomes Zombie or Defunct.Its main resources are released by Kernel, but it still present in Process Table until Parent will read its status.If a parent process terminated without wait()-ing for its children, the parent PID of each child process is set to 1.

Zombie Process

Parent Child

Kernel

fork

exitwait

Exit Status:1 low-order byte

Process Status:2 low-order bytes

Page 5: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-5© D.Zinchin [[email protected]]

Waitpid System Call #include <sys/wait.h>pid_t waitpid (pid_t pid, int *p_status, int options);

• Waits for one of the children process to finish (performs functionality of wait with additional options).• The pid argument may be: > 0 - PID of particular process = 0 - sender’s process group =-1 - all sender’s processes <-1 - process group ID = abs(pid)

• The options argument may be:

WNOHANG - check status of terminated processes in non-blocking mode WUNTRACED - report also the status of stopped child processes• If p_status is not NULL, the 2 low-order bytes will be filled with Process Status information.• Returns: child PID > 0 of child process terminated with exit system call or with signal,

-1 - if there aren’t child processes,-1 (errno=EINTR) - if wait interrupted with signal,

-1 (errno=ECHILD) - if argument pid is invalid,-1 (errno=EINVAL) - if argument options is invalid, 0 - if WNOHANG option is specified and child process(es) still running

WIFEXITED(status), WEXITSTATUS(status),

WIFSIGNALED(status), WTERMSIG(status),

WIFSTOPPED(status), WSTOPSIG(status)

Process Status Evaluation

Process Status High Order byte

Low Order byte

Terminated due to exit() Exit Status 0

Terminated by signal 0 Signal Number

Stopped( reported only by waitpid() )

Signal Number WSTOPFLG

To evaluate process status the following MACROs are used: int * p_status

Logical (0/1)

Arithmetical:( Exit Status / Signal Number )

Page 6: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-6© D.Zinchin [[email protected]]

Exec System Call

• Executes the program as existing process, replacing current process image with new one.

• Program arguments could be passed as NULL-terminated list (arg0,…,argN) or vector (argv[ ]),

argument 0 would specify program name, arguments 1-N specify parameters.

• Target program file could be specified by path or as file name to be used with PATH variable.

• In form with envp argument, also replaces new image environment.

• It is an only way in which a program is executed in UNIX.

• As result of exec…() system call the following process

attributes could be changed:

- Effective User ID

- Effective Group ID

- Initial Environment Vector

- The signals, which were set to be caught by caller,

are changed to terminate the new program

(because code of old signal handlers became unavailable)

• In case of error exec() returns -1, errno indicates the error.

#include <unistd.h>int execl (const char *path, const char *arg0, ..., const char *argn, char * /*NULL*/);int execv (const char *path, char *const argv[ ]);

int execlp (const char *file, const char *arg0, ..., const char *argn, char * /*NULL*/);int execvp (const char *file, char *const argv[ ]);

int execle (const char *path, const char *arg0, ..., const char *argn, char * /*NULL*/, char *const envp[ ]);int execve (const char *path, char *const argv[ ], char *const envp[ ]);

sh fork

prog1

prog2

fork

exec

exec

Example: Starting two new programs from Shell

init getty login /bin/sh

forkexec exec exec

initPID=1

ask credentials

check password, load user configuration

How user session is started.

Example: execute “ls ./”

execl(“/bin/ls”, “ls”, “./”, NULL);

Page 7: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-7© D.Zinchin [[email protected]]

File System Management (Input/Output) System Calls

createerrorO_...|O_CREAT|O_EXCL (mode used)

createopenO_...|O_CREAT (mode used)

erroropenO_...

No

File exists

O_CREAT and O_EXCLFlags Combination: Yes

With each File, open by specific Process, the Kernel associates the unique integer value in the scope of this process.

This integer key is named File Descriptor. It is used as file identifier for all subsequent read and write operations.

By default, the File Descriptors 0, 1 and 2 are associated with Standard Input, Output and Error correspondently.

#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int open (const char *path, int oflag, …/*mode_t mode*/);

• Opens file specified by path-name• Argument oflag specifies one of following open modes:

O_RDONLY (=0) read-only, O_WRONLY (=1) write-only, O_RDWR (=2) read & write• The following bit flag values could be added with bitwise-OR operator (see also man):

O_APPEND - all writes append data to the end of file

O_TRUNC - if open for write, the file is truncated to 0 bytes length

O_CREAT - file will be created if it does not exist yet

O_EXCL - used with O_CREAT for exclusive creation• Argument mode is used with O_CREAT flag and specifies

the permissions of creating file as octal constant.• Returns File Descriptor (>=0) in case of success.

Returns -1 in case of error, errno value specifies the error (see man).

• Deallocates File Descriptor specified by fd.

This File Descriptor could be reused by subsequent open() calls.• Returns 0 on success. Returns -1 in case of error, errno value specifies the error.

#include <unistd.h>int close (int fd);

Process

0 1 2 3 N…4

std

ou

t

std

in

std

err

File

A

Example. Open File

fd=open(“FileA”, O_RDWR);/* As result, fd equal 3 */

file descriptors

Page 8: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-8© D.Zinchin [[email protected]]

I/O System Calls (continuation)#include <unistd.h>ssize_t read (int fd, void *buf, size_t nbyte);

• Reads no more than nbyte-s from file associated with descriptor fd into buffer buf.• Returns non-negative number of read bytes. Returns -1 in case of error, errno value specifies the error.

• Writes nbyte-s from buffer buf to the file associated with descriptor fd .• Returns non-negative number of written bytes. Returns -1 in case of error, errno value specifies the error.

#include <unistd.h>ssize_t write (int fd, void *buf, size_t nbyte);

• Sets the file pointer associated with the open file descriptor fd as follows: - if whence == SEEK_SET, the pointer is set to offset bytes from file beginning. - if whence == SEEK_CUR, the pointer is set to its current location plus offset. - if whence == SEEK_END, the pointer is set to the size of the file plus offset.• Returns the resulting offset calculated from file beginning. Returns -1 in case of error, errno specifies the error.

#include <sys/types.h>#include <unistd.h>off_t lseek (int fd, off_t offset, int whence);

The Standard C Library provides the data type FILE representing Buffered Stream Object and set of functions

providing Buffered Input / Output: fopen(), fclose(), fread(), fwrite(), fseek(), fflush().

Actually, the object of type FILE is buffered wrapper of File Descriptor, associated with corresponded file.

The following utility function associates the buffered stream object of type FILE with already open File Descriptor:

#include <stdio.h>FILE *fdopen (int fd, const char *mode);

• Associates Buffered Stream with already open File Descriptor.• Argument mode could have the same values (“r”, “w”, “a”, “r+”, “w+”, “a+”) as for fopen() function.• Returns FILE* pointer to Buffered Stream object or NULL in case of error.

Buffered Input / Output

Page 9: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-9© D.Zinchin [[email protected]]

Dup System Calls and Redirection

#include <unistd.h>int dup (int fd);

• Duplicates an open file descriptor

• Returns a new file descriptor pointing to the same file

or -1 in case of failure (errno indicates the error)

• The file descriptor returned is the lowest one available.

• The new file descriptor is set to remain open across exec

functions.

int dup2(int fd1, int fd2);

• Duplicates an open file descriptor

• Causes the file descriptor fd2 to refer to the same file as fd1.

• If fd2 already refers to an open file, not fd1, it is closed first.

• If fd2 already refers to fd1, or if fd1 is not valid, fd2 will not be

closed first.

• Returns non-negative value of fd2 in case of success

or -1 in case of failure (errno indicates the error)

Process

0 1 2 3 N…4

Process

0 2 3 N…4

Process

0 1 2 3 N…4

1

std

ou

t

std

in

std

err

File

A

std

ou

t

std

in

std

err

File

A

std

ou

t

std

in

std

err

File

A

Process

0 1 2 N…4

std

ou

t

std

in

std

err

File

A

3

fd=open(“FileA”…);

/* fd equal 3 */

close(1);

dup(fd));

close(fd));

Example. Redirection of STDOUT to File

file descriptors

Example. dup2() via dup()

close(1);dup(fd);

dup2(fd, 1);

Page 10: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-10© D.Zinchin [[email protected]]

Inter Process and Inter-Host Communication

Inter Process Communication (IPC) is sharing of information and resources by two or

more different processes.

Kernel

host• IPC includes

- Data Exchange

- Synchronization

• UNIX (Linux) provides different methods of IPC:

- Pipes

- FIFOs

- Signals

- Message Queues

- Shared Memory

- Semaphores

Process 1 Process 2

Kernel

host 1

Process 1

Kernel

host 2

Process 2

Inter-Host Communication (IHC)is IPC between two or more processes, running on

different hosts in the network.

• UNIX (Linux) provides the following methods for IHC:

- Berkeley Socket API

- System V Transport Library Interface (TLI)

Page 11: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-11© D.Zinchin [[email protected]]

Unnamed Pipe

#include <unistd.h>int pipe (int *fd);

• Creates input / output mechanism called the Pipe. The Pipe is unidirectional bite stream

• Through fd[0] the read descriptor is returned.

Through fd[1] the write descriptor is returned.

• The Pipe is usually used for communication between Parent and Child Processes.

• The pipe() call returns 0 in case of success. In case of failure -1 is returned, errno indicates the error.

Process 1

W R

pipe

kernel

Process 1

W R

pipe

kernel

Process 2

W R

Process 1

W R

pipe

kernel

Process 2

W R

int fd[2];pipe(fd);

childpid=fork();close(fd[0]); close(fd[1]);

Page 12: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-12© D.Zinchin [[email protected]]

Unnamed Pipe Usage Scenarios

Process 1

W R

pipe2

kernel

Process 2

W R

pipe1

Bidirectional flow

• Bidirectional flow needs 2 pipes

pipe1

Process 1 Process 2 Process 3

W W R

2 Processes write to 1

• If a process writes less than Capacity of Pipe

(which is at least 4096), the write operation is

guaranteed to be atomic.

• In Special cases:

- read & no data

- write & pipe is full

the behavior depends on blocking / non-blocking mode (flag O_NONBLOCK or O_NDELAY)

• If one end closed while second is writing, the SIGPIPE signal is sent to writing peer.

fork fork fork

Page 13: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-13© D.Zinchin [[email protected]]

Example of Pipe Usage

Parent – “Client”pipe(pipe1);pipe(pipe2);fork();/* close descriptors unused by client: P1[0] - close, P1[1] - P1 write P2[0] - P2 read, P2[1] - close*/close(pipe1[0]);close(pipe2[1]);

… do Client functionality…

/* close descriptors used by client */close(pipe1[1]);close(pipe2[0]);exit(0);

Parent-”Client”

W R

pipe2

kernel

Child-”Server”

W R

pipe1

fork

0 1 F

STDIN

STDOUT

File

read file name

print file contentsor error

read

file contents

open file

response

request

Child-”Server”

/* close descriptors unused by server: P1[0] - P1 read, P1[1] - close P2[0] - close, P2[1] - P2 write*/close(pipe1[1]);close(pipe2[0]);

… do Server functionality…

/* close descriptors used by server */close(pipe1[0]);close(pipe2[1]);exit(0);

Page 14: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-14© D.Zinchin [[email protected]]

Pipe-related Library Functions #include <stdio.h>

FILE *popen(const char *command, const char *mode); int pclose(FILE *stream);

• Function popen() creates a pipe between the calling program and the command to be executed.• The command argument consists of a shell command line, that is invoked as follows:

execl("/usr/xpg4/bin/sh", "sh", "-c", command, NULL);

• The mode argument is either “r” for reading or “w” for writing.• Depending on mode, calling program could read from STDIN or write to STDOUT of the command.• Function pclose() closes a pipe, waits for the associated process and returns its termination status.

Example: Using popen() to run “ls *.c”

#include <stdio.h> #include <stdlib.h> int main() { char *cmd = "/usr/bin/ls *.c"; char buf[BUFSIZ]; FILE *ptr;

if ((ptr = popen(cmd, "r")) != NULL) { while (fgets(buf, BUFSIZ, ptr) != NULL) printf("%s", buf); pclose(ptr); }}

#include <stdlib.h>

int system(const char *string)

• Function system() invokes string as shell command, waits until the shell completion and return its status.

• This function could be used only if single-threaded process.

• In multi-threaded process the following code could replace functionality of system():

pclose(popen(string,”w”));

Page 15: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-15© D.Zinchin [[email protected]]

FIFO or Named Pipe #include <sys/stat.h>

int mknod(const char *path, mode_t mode, dev_t dev);

• The system call mknod() creates a filesystem node (file, device special file or named pipe)

• The FIFO (First In, First Out) is unidirectional bite stream with persistent name.

• FIFO (Named Pipe) is created by the command mknod or by system call mknod() with

mode=(S_IFIFO | permissions)

• Upon successful completion, mknod() returns 0. Otherwise, it returns -1, and errno is set to indicate the error.

• FIFO is opened for writing / reading as regular file by its name (open(), close(), fopen(), fclose()).

• Process, opening FIFO for writing, waits (is blocking) until the second process opens FIFO for reading.

• To communicate through FIFO the processes don’t have to be in Parent-Child relation.

• In Special cases ( read & no data, write & pipe is full ) the behavior depends on blocking / non-blocking mode

(flag O_NONBLOCK or O_NDELAY) Process 1

W

FIFO <FifoName>

kernel

Process 2R

Process 1mknod(FifoName, S_IFIFO | perms, 0);

open(FifoName, O_WRONLY);

Process 2open(FifoName, O_RDONLY);

#include <unistd.h> int unlink(const char *path);

• The unlink() function removes a link to a file.• When the file's link count becomes 0 and no process has the file open, the file is deleted

Page 16: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-16© D.Zinchin [[email protected]]

Blocking Mode and Special Conditionsof I/O operations on Pipes and FIFOs

Condition Normal (Blocking) Mode Non-Blocking ModeO_NONBLOCK

• open FIFO for read• writer doesn’t exist

Waits until writer opens FIFO for write

Returns immediately, no error

• open FIFO for write• reader doesn’t exist

Waits until reader opens FIFO for read

Returns immediately with error, errno=ENXIO

• read from Pipe / FIFO• no data

Waits until:• writer writes data (return amount of data)• or writer is closed (return 0)

Returns immediately with error,errno= EAGAIN

• write to Pipe / FIFIO• the Pipe / FIFO is full

Waits until space is available, write the data

Returns immediately with error,errno= EAGAIN

• read from Pipe / FIFO• writer close its side descriptor

Returns immediately with value 0

• write to Pipe / FIFO• reader closed its side descriptor

Returns with error, errno=EPIPESignal SIGPIPE is sent, its default action - to terminate the process

Flag O_NONBLOCK or O_NDELAY could be specified

• during open()-ing of FIFO descriptor

• with function fcntl() on already open Pipe or FIFO descriptor

#include <unistd.h>#include <fcntl.h>

int fcntl(int fildes, int cmd, /*arg*/ ...);

• Function fcntl() provides miscellaneous operations on file descriptors• To set non-blocking I/O mode, the following form is used:

int flags = fcntl (fd, F_GETFL, 0); /* get current flags */

fcntl (fd, F_SETFL, flags | O_NONBLOCK); /* add non-blocking flag */

On some UNIX systems flag O_NDELAY specifies different behavior, than O_NONBLOCK

On some UNIX systems if flag O_NDELAY is specified instead of O_NONBLOCK, the value 0 is returned.

Page 17: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-17© D.Zinchin [[email protected]]

Example: FIFO-based Client-Server Model

ClientW

Server FIFOuses well-known

SERVER_FIFO Name

kernel

ServerRR

Client FIFOuses temporary

Client FIFO Name

W

Server:

- Creates Server FIFO with well-known name

- Opens Server FIFO for read (blocking)

- Opens Server FIFO for write to avoid read unblocking

- Waits (blocking read) for incoming client request

- Reads Client FIFO Name from Client Request

- Opens Client FIFO to write

- Writes the Reply

- Closes Client FIFO.

- (repeat for each client)

- (On termination) Closes and deletes Server FIFO

Client:

- Creates Client FIFO with unique temporary name

- Opens Server FIFO for write

- Writes Request, containing Client FIFO name

- Closes Server FIFO.

- Opens Client FIFO for read

- Reads the Reply

- Closes and deletes Client FIFO.

w

Page 18: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-18© D.Zinchin [[email protected]]

Iterative and Concurrent Server

Start-up

Bind to well-known address

Waitfor Clients

Read Client Request

Connectto Client Address

SendReply to Client

DisconnectFrom Client

Continue?

Disconnect fromwell-known address

Start-up

Bind to well-known address

Waitfor Clients

Read Client Request

Connectto Client Address

SendReply to Client

DisconnectFrom Client

Continue?

Disconnect fromwell-known address

ForkSub-Server

Connect to Serverby well-known address

Send Request

Wait forReply

ReadReply

Disconnectfrom Server

Start-up

Bind to ephemeral address

yes

yesno

no

release defuncts

IterativeServer

Client ConcurrentServer

Sub-Server

Disconnect fromephemeral address

Page 19: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-19© D.Zinchin [[email protected]]

Signal

Name Value Default Event===========================================================SIGHUP 1 Exit Hangup on controlling terminal SIGINT 2 Exit Interrupt (Ctrl-C)SIGQUIT 3 Core Quit – interactive terminationSIGILL 4 Core Illegal InstructionSIGTRAP 5 Core Trace or Breakpoint TrapSIGABRT 6 Core Abort – abnormal terminationSIGEMT 7 Core Emulation TrapSIGFPE 8 Core Arithmetic ExceptionSIGKILL 9 Exit Killed (can’t be changed)SIGBUS 10 Core Bus Error (undefined memory access)SIGSEGV 11 Core Segmentation Fault (invalid memory reference)SIGSYS 12 Core Bad System CallSIGPIPE 13 Exit Broken PipeSIGALRM 14 Exit Alarm Clock (timeout signal)SIGTERM 15 Exit TerminatedSIGUSR1 16 Exit User Signal 1SIGUSR2 17 Exit User Signal 2SIGCHLD 18 Ignore Child Status ChangedSIGPWR 19 Ignore Power Fail or RestartSIGWINCH 20 Ignore Window Size ChangeSIGURG 21 Ignore Urgent Socket ConditionSIGPOLL 22 Exit Pollable Event SIGSTOP 23 Stop Stopped (can’t be changed)SIGTSTP 24 Stop Stopped (user) (Ctrl-Z)SIGCONT 25 Ignore Continued (command fg)SIGTTIN 26 Stop Stopped (tty input) SIGTTOU 27 Stop Stopped (tty output)SIGVTALRM 28 Exit Virtual Timer ExpiredSIGPROF 29 Exit Profiling Timer ExpiredSIGXCPU 30 Core CPU time limit exceeded SIGXFSZ 31 Core File size limit exceeded

Signal is software interrupt used as notification to process about some event.

Process accepts a signals:• sent by Kernel• sent by another process

• Sends a signal to the process(es) specified by each pid operand.• The pid argument may be: >0 - PID of particular process =0 - sender’s process group -1 - all sender’s processes <-1 - process group ID = abs(pid)• With -l parameter writes all supported signal names

/usr/bin/kill -s signal_name pid... [-signal_name] pid... [-signal_number] pid... -l

UNIX utility kill

Example:

Send SIGINT to process with PID=12345

# kill -s INT 12345

# kill -INT 12345

# kill -2 12345

Page 20: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-20© D.Zinchin [[email protected]]

Sending and Handling the Signal#include <sys/types.h>#include <signal.h>

int kill(pid_t pid, int sig);

• System call kill() sends a signal to a process or a group of processes.• The sender and receiver must have the same effective user ID or sender must be superuser.• Sending sig = 0 used to check process existence.• The pid argument could have the following values:

>0 - PID of particular process=0 - sender’s process group-1 - all sender’s processes<-1 - process group ID = abs(pid)

• The kill() call returns 0 in case of success. In case of failure -1 is returned, errno indicates the error.

#include <signal.h>

void (*signal (int sig, void (*sig_handler)(int) ) ) (int);

this is equivalent of

typedef void( *sig_handler) (int sig);

sig_handler signal(int sig, sig_handler handler);

• System call signal() modifies signal disposition. • The sig specifies any signal, excepting SIGKILL and SIGSTOP. • The sig_handler argument specifies the signal's disposition, which may be:

- SIG_DFL - to provide default signal handling - SIG_IGN - to ignore the signal - user-defined handler name - to provide specific signal handling with specific handler

• The signal() call returns the previous handler (disposition) of the signal.

#include <unistd.h>

int pause(void);

•System call pause() suspends the calling process until it receives a signal. • If process is not terminated by signal, returns value -1 and sets errno=EINTR

int raise(int sig);

• Sends the signal sig to executing program. • Is equivalent to kill(getpid(), sig)

Page 21: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-21© D.Zinchin [[email protected]]

Signal Handling

ExamplesExample 1. Suspend / Resume application output with SIGINT signal (sent with Ctrl-C).

#include <signal.h>int flag=0;

/*--- Signal SIGINT handler--- */void sigreact (int sig){ /* OS-depended re-subscription*/ /* signal(SIGINT,sigreact); */ flag = ! flag;}…/*--- Prints application data ---*/void printInfo(…){ … /* subscribe to signal */ signal (SIGINT, sigreact); while(…/*has more data */)

{ while(flag) { /* wait for signal */ pause ( ); }

printf(…/*print the data*/);

}

/* unsubscribe from signal */ signal (SIGINT, SIG_DFL); … }

Example 2.

Using alarm() System Call to provideoperation timeout.

#include <stdio.h> #include <unistd.h> #include <signal.h>

char userName[MAXBUFF];

/* --- Alarm signal handler. --- */void catch_alarm(int sig_num){ perror("Operation timed out."); exit(0);}…/* --- Reads user name --- */int main(int argc, char* argv[]){ /* subscribe for ALRM signals */ signal(SIGALRM, catch_alarm); /* prompt the user for input */ printf("Username: "); fflush(stdout); /* start a 30 seconds alarm */ alarm(30); /* wait for user input */ fgets(userName, MAXBUFF, stdin);

/* remove the timer*/ alarm(0);

printf("User name: '%s'\n", userName); return 0;}

#include <unistd.h>

unsigned intalarm (unsigned int sec);

• Causes the system to generate a SIGALRM signal for the process after the number of sec real-time seconds.• If sec = 0, a pending alarm request, if any, is cancelled.• Alarm requests are not stacked. Each alarm() call reschedules the alarm time.• The fork() call clears pending alarms in the child process.

Page 22: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-22© D.Zinchin [[email protected]]

Race ConditionRace Condition or Race Hazard

This is a defect of Process functionality, when behavior of the process

is unexpectedly and critically depends on the sequence or timing of occurring events.

Most common scenario: two events (or signals) are racing each other to affect the Process.

This is Critical Region

void sigreact (int sig){ flag = ! flag;}void someProcedure(){… flag = 1; /* subscribe to signal */ signal (SIGINT, sigreact);…… /* wait for signal */ while(flag) { pause ( ); } /* continue execution */…

If signal arrives here, flag will be changed to 0, pause() call will not be performed,process execution will continue

If signal arrives here, flag will be changed to 0, pause() call will be interrupted,and process execution will continue

If signal arrives after check of flag flag will be changed to 0, but pause() call will be performed,process will be “stuck”

Race Condition Example

Two “racing” events are:

• Flag testing by procedure

• Flag setting by signal handler

Critical Region

This is the region of code, where occuring of event (or signal) causes Race Condition.

Page 23: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-23© D.Zinchin [[email protected]]

Avoiding of Race ConditionThere are two ways to avoid Race Condition :

1) To perform the Polling - repeatable check of the resource state with limited time period

In previous example this means to replace system call pause( ) with call to function sleep(int seconds).

Advantage:

This is the simplest way to avoid process forever “sticking”.

Disadvantage:

In certain condition, process will be able to recognize state update only after delay .

In previous example, if signal will occur after flag check, but before sleep() call, the process will

be able to recognize flag update only after expiration of next sleep timeout

2) To provide Blocking of event (signal) delivery in the Critical Region.

In previous example this means to prohibit delivery of specific signal SIGINT between flag check and

system call pause( ).

Advantage:

The event (signal) delivery delay will be minimized.

Event (signal) will be delivered as soon as Critical Region will be passed.

Disadvantage:

Requires more complicated blocking mechanism to be provided by Kernel

Note:In most the cases the Race Condition occurs between test and set operations.To avoid “racing” of test and set, the Kernel provides number of tools (system calls),performing test-and-set as one impartible operation.

Page 24: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-24© D.Zinchin [[email protected]]

Signal BlockingSignal Blocking is temporary prevention of signal delivery.

Each process has Process Signal Mask, specifying the set of signals, which currently blocked by the process.

Blocked signals (unlike ignored signals) do not get lost. If generated signal is specified as blocked,

the process holds the occurrence of this signal in Pending Signal Mask until signal is unblocked.

After unblocking, the pending signal is delivered (the specified action is performed).

Is Signal ignored ?

Unblock the Signal (remove from Signal Mask)

Signal Generation

Add occurrence to Pending Signal Mask

yes

yes no

no

yes

no

Eventoccurred

Process Flow

Is Signal blocked ?

Block the Signal (add to Signal Mask)

Discard the SignalDeliver the Signal

(take proper action)

Remove occurrence from Pending Signal

Mask

Is Signal pending ?

Start the Process (init Signal Mask)

Signal Delivery Diagram

process

flow

signal

blocking

signal

unblocking

Page 25: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-25© D.Zinchin [[email protected]]

POSIX Signal Set Utilities

POSIX Signal Set

To provide system calls on set of signals, POSIX standard provides data type sigset_t, representing the Signal Set.

This type contains the set of bit flags. Each bit flag corresponds to specific signal.

For manipulation with POSIX Signal Set the following service functions are used :

#include <signal.h>

int sigemptyset(sigset_t *set); - removes all signals from the Signal Set

int sigfillset(sigset_t *set); - fills the Signal Set with all the signals

int sigaddset(sigset_t *set, int signum); - adds the specified signal to the Signal Set

int sigdelset(sigset_t *set, int signum); - deletes the specified signal from the Signal Set

int sigismember(const sigset_t *set, int signum); - checks if a specified signal is in the Signal Set

• All these functions return 0 on success, -1 on error.

• The sigismember() function returns 1(=true) / 0(=false) / -1 (error).

Page 26: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-26© D.Zinchin [[email protected]]

POSIX System Calls for Signal Blocking#include <signal.h>int sigprocmask (int how, const sigset_t *set, sigset_t *oldset);

• System call sigprocmask() is used to change / examine the Signal Mask (set of blocked signals) of the calling process• Parameter how may have the following values

-SIG_BLOCK - the Signal Set, specified by set, is added to process Signal Mask-SIG_UNBLOCK - the Signal Set, specified by set, is removed from process Signal Mask-SIG_SETMASK - the Signal Set, specified by set, replaces the process Signal Mask

• If oldset is not NULL, the old Signal Mask value is returned• If set is NULL, the process Signal Mask is not modified.• If any pending signals became unblocked during the call, at least one of those signals will be delivered before the call to sigprocmask() returns.• Attempts to block signals SIGKILL, SIGTOP are silently ignored.• Return values: 0-success, -1 failure (errno will specify the error).

• System call sigsuspend() performs the following operations:

- temporary replaces Signal Mask;

- suspends the calling process until it receives a signal;

- restores the Signal Mask ,

if process is not terminated by signal.• If process is not terminated, returns -1 and sets errno = EINTR

#include <signal.h>int sigsuspend (const sigset_t *set);

Commonly the sigprocmask() call is used to block Signal delivery in Critical Region.The sigsuspend() call is used to wait for the signal out of Critical Region.

#include <signal.h>int sigpending (sigset_t *set);

• System call sigpending() function retrieves

those signals that have been sent to the

process but are being blocked from delivery

by the calling process's signal mask. • The result stored in set argument.

• Returns 0 on success, -1 on failure.

Page 27: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-27© D.Zinchin [[email protected]]

Race Condition Resolutionvoid sigreact (int sig){ flag = ! flag;}

void someProcedure(){… sigset_t blockMask, unblockMask; /* prepare masks */ sigemptyset ( &blockMask); sigaddset ( &blockMask, SIGINT); sigprocmask ( SIG_SETMASK, NULL, &unblockMask); sigdelset ( &unblockMask, SIGINT);

flag = 1; /* subscribe to signal */ signal (SIGINT, sigreact);… /* block the signal */ sigprocmask (SIG_BLOCK, &blockMask, NULL);… /* wait for signal */ while(flag) { sigsuspend ( &unblockMask); } /* continue execution */…

If signal arrives here, flag will be changed to 0, then sigsuspend () will not be called,process execution will continue

Here signal is blocked.If it will arrive,Pending Signal MaskWill be updated, but signal will not be delivered.

Race Condition Resolution

Example

Critical RegionIs covered.

Here the signal (pending or generated)is safely handled

Page 28: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-28© D.Zinchin [[email protected]]

POSIX Advanced Signal Handling#include <signal.h>int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);where:

struct sigaction { void (*sa_handler)(int); sigset_t sa_mask; int sa_flags;};

• The sigaction() system call provides POSIX advanced (relatively to signal() ) interface, used to change the action taken by a process on receipt of a specific signal.• Parameter signum specifies the signal number. Parameters act and oldact specify the pointers to the structures, describing old and new action to be taken on specified signal delivery.• The structure sigaction specifies the following fields: sa_handler - the signal handling function sa_mask - a mask of signals which should be blocked during execution of the signal handler. (the signal which triggered the handler will also be blocked, unless the SA_NODEFER flag is used) sa_flags - specifies a set of flags used to modify the delivery of the signal (flags are combined with logical OR) Some of sa_flags values: SA_RESETHAND - Restore the signal action to the default state once the signal handler has been called. SA_RESTART - Provide restart of “slow” system calls, interrupted by signal . SA_NODEFER - Do not prevent the signal from being received from within its own signal handler. • Returns 0 – success,

-1 – failure (errno specifies the error).

void handler(int sig){…}…

struct sigaction newAction; newAction.sa_handler=handler; /* set the handler*/sigfillset(&newAction.sa_mask); /* block other signals during the handling */newAction.sa_flags = 0; /* no flags */if (sigaction(SIGUSR1, &newAction, NULL) < 0){…}

Example: Signal handling with sigaction()

Page 29: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-29© D.Zinchin [[email protected]]

System V IPCSystem V IPC provides three methods:

-Shared Memory Segments-Message queues-Semaphores

All these IPC methods have similar access interface:

persistent integer KEY name and integer system ID.

MethodName Space

(name given by user)Identification

(ID given by Kernel)

Unnamed Pipe No Name File Descriptor

FIFO Pathname File Descriptor

System V IPC KEY , 32-bit integer ID, integer

UNIX IPC-related Utilities ipcsReport IPC facilities status

ipcrm [-m id] [-q id] [-s id] [-M key] [-Q key] [-S key]Removes IPC object by ID or by KEY.

#ipcsIPC status from <running system> as of Thu Feb 1 12:11:56 IST 2007T ID KEY MODE OWNER GROUPMessage Queues:q 0 0xd9019340 --ra-r--r-- root rootq 1 0xd9719343 --ra-r--r-- root rootq 2 0xd9089388 --ra-r--r-- root rootShared Memory:m 0 0x1e34 --rw-rw-rw- root otherm 257 0x79ebc2ac --rw-r----- oracle dbam 258 0x17220c --rw-r----- oracle dbam 259 0x4d0190d2 --rw-rw-rw- temip temip_usm 260 0x300192ed --rw-rw-rw- temip temip_usm 261 0x300192d0 --rw-rw-rw- temip temip_usSemaphores:s 0 0xf9019340 --ra-r--r-- root roots 65539 0xf9019349 --ra-r--r-- root roots 65540 0xf901934a --ra-r--r-- root root

#include <sys/ipc.h>typedef int key_t;key_t ftok(const char *path, int prm_char);

How to build the KEY for System V IPC object

#include <sys/ipc.h>#define IPC_PRIVATE (key_t)0 /* private key */

• The ftok() function returns a key based on path

and additional prm_char (only 8 bits used)• Returns the same values for the different path

names of the same existing file

and same prm_char• Returns -1 if path does not exist or is not

accessible

• May be used by process as ephemeral KEY

KEY

Predefined (well-known) value

Ephemeral (IPC_PRIVATE) value

Path

Prm_charftok

Page 30: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-30© D.Zinchin [[email protected]]

System V Shared Memory

Server

W

pipe

kernel

Client

R R

InputFile

OutputFile

W

read() read()write() write()

memory memoryServer

kernel

Client

R

InputFile

OutputFile

W

read()write()

SharedMemory

Shared Memory is the fastest form of IPC available. Once the Shared Memory region is mapped into the address space of the processes,

no kernel involvement occurs in passing data between the processes.

Data copied 4 times Data copied 2 times

Note:Access to Shared Memory from different processes

must be synchronized

Page 31: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-31© D.Zinchin [[email protected]]

Access and Control Shared Memory

#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>

int shmget(key_t key, size_t size, int flags);

• Creates new Shared Memory segment with specified size if:

- key = IPC_PRIVATE or

- key does not refer to existing segment

and IPC_CREAT flag specified• If segment was created or already exist, returns segment ID.• Returns -1 in case of error, errno specifies the error.

In combination with IPC_CREAT – return an error, if segment already existsIPC_EXCL

Create if does not existIPC_CREAT

Write by others0002

Read by others0004

PermissionsWrite by group0020

AccessRead by group0040

Write by owner0200

Read by owner0400

flags:

createerrorperms | IPC_CREAT | IPC_EXCL

createopenperms | IPC_CREAT

erroropenperms

No

Segment existsFlags

Combination: Yes

#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>

struct shmid_ds {…/* see man */…};int shmctl(int shmid, int cmd, struct shmid_ds *buf);

• Performs control operations on Shared Memory.

• The cmd may be: IPC_STAT, IPC_SET, IPC_RMID, IPC_LOCK, IPC_UNLOCK

• To remove Shared Memory segment, used in following form:

shmctl(shmid, IPC_RMID, NULL);

• Returns 0 in success, -1 in case of error (errno specifies the error)

Page 32: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-32© D.Zinchin [[email protected]]

Attach / Detach Shared Memory

#include <sys/types.h>#include <sys/shm.h>

void *shmat(int shmid, const void *addr, int flags);

• Attaches Shared Memory segment, specified by ID, to the Data Segment of the calling process:

addr = NULL – attached to address selected by system

addr != NULL – attached to specified address (see flags)

• Specific flags value:

SHM_RDONLY – read only access

• Returns:

the segment starting address on success,

-1 in case of failure (errno specifies the error)

#include <sys/types.h>#include <sys/shm.h>

int shmdt(const void *shmaddr);

• Detaches Shared Memory segment from the calling process.

• Returns 0 (success) / -1 (failure)

Page 33: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-33© D.Zinchin [[email protected]]

Shared Memory Example/* -- server main -- */include “common.h”main(){ int shmid; key_t key; char *shm; /* Create the segment. */ shmid = shmget(THE_KEY, THE_SIZE, PERMS | IPC_CREAT | IPC_EXCL); if (shmid < 0) { … /*handle error*/ }

/* Attach the segment to server data space. */ shm = shmat(shmid, NULL, 0); if (shm == (char *) -1) { … /*handle error */ }

/* Put some data to be read by another process. For example: */ strcpy(shm, “Any Data”);

/* Notify the client and wait until read finish */ ...

/* Detach the segment */ if (shmdt(shm) == -1){ …/*handle error*/ }

/* Remove the segment */ if (shmctl(shmid, IPC_RMID, NULL) == -1 ){ …/*hanlde error*/ }}

/*-- client main -- */#include “common.h”main(){ int shmid; key_t key; char *shm, buf [THE_SIZE];

/* Get the segment ID */ shmid = shmget(THE_KEY, THE_SIZE, PERMS); if (shmid < 0) { …/*handle error*/ }

/* Attach the segment to client data space. */ shm = shmat(shmid, NULL, 0); if (shm == (char *) -1) { …/*handle error*/ }

/* Wait notification from server to begin read */ …

/* Read the data from server. For example:*/ strcpy(buf, shm);

/* Notify the server about read finish */ …

/* Detach the segment */ if (shmdt(shm) == -1){ …/*handle error*/ }}

/*-- common.h --*/#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>

#define THE_KEY 5678#define THE_SIZE 100#define PERMS 0666

Page 34: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-34© D.Zinchin [[email protected]]

Example: Shared Memory - based Client-Server Modelwith Signal Synchronization

Server:

- Creates Shared Memory with well-known KEY_T name

- Attaches Shared Memory

- Writes own PID to “Server PID” field

- Subscribes for signal notification from Client

- Writes 0 to “Client PID” field

- Waits for signal from new Client

- Reads from “Client PID”, “Data Length”, “Data Buffer”

- Opens requested File for read

- Writes data portion to “Data Buffer”, fills “Data Length”

- Sends notification signal to Client by PID

- Waits for signal from Client

- (repeats until empty portion is written)

- (repeats for each client)

- Detaches Shared Memory

- Removes Shared Memory

Client:

Gets Shared Memory ID by well-known KET_T name

- Attaches Shared Memory

- Reads Server PID from “Server PID” field”

- Subscribes for signal notification from Server

- Checks if “Client PID” is 0 and writes there own PID

- Writes null-terminated File Name to “Data Buffer”

field and its length to “Data Length” field

- Sends notification signal to Server by PID

- Waits for signal from Server

- Reads reply portion from “Data Buffer”

- Sends notification signal to Server by PID

- (repeats until empty portion was read)

- Detaches Shared Memory

ServerClient Server PID Client PID Data BufferData Length

4 bytes N bytes4 bytes 4 bytes

Shared Memory

Page 35: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-35© D.Zinchin [[email protected]]

System V Message QueueMessage Queue is persistent queue of messages stored in Kernel.

As any other System V IPC objects, Message Queue is identified by KEY_T name and ID.

Processes read and write messages to arbitrary queues.

Sender process can write the message and exit. Receiver process can read the message later.

Every message in queue has the following attributes:

• Type – long integer type value

• Length – the length of data portion of the message ( >=0 )

• Data – any data ( if Length > 0 )

The Message Queue could be considered as linked list of messages .

For each Message Queue the Kernel maintains the structure msqid_ds, holding the current state of this Queue.

kernelstruct msqid_ds

msg_first

msg_last

msg_ctime

msqid

type = 100msg_permstructure

link

length = 1

data

type = 200

link

length = 2

data

type = 300

NULL

length = 3

data. . .

- time of last change

Page 36: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-36© D.Zinchin [[email protected]]

Message Queue Access and Control

#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>

int msgget(key_t key, int flags);

• Creates new Message Queue with specified size if:

- key = IPC_PRIVATE or

- key does not refer to existing segment

and IPC_CREAT flag specified• If queue was created or already exist, returns queue ID.• Returns -1 in case of error, errno specifies the error.

In combination with IPC_CREAT – return an error, if queue already existsIPC_EXCL

Create if does not existIPC_CREAT

Write by others0002

Read by others0004

PermissionsWrite by group0020

AccessRead by group0040

Write by owner0200

Read by owner0400

flags:

createerrorperms | IPC_CREAT | IPC_EXCL

createopenperms | IPC_CREAT

erroropenperms

No

Queue existsFlags

Combination: Yes

#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>

struct msqid_ds {…/* see man */…};int msgctl(int msqid, int cmd, struct msqid_ds *buf);

• Performs control operations on Message Queue.

• The cmd may be: IPC_STAT, IPC_SET, IPC_RMID

• To remove Message Queue, used in following form:

msgctl(msqid, IPC_RMID, NULL);

• Returns 0 in success, -1 in case of error (errno specifies the error)

Page 37: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-37© D.Zinchin [[email protected]]

Send Message to Message Queue

#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>

struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1]; /* message data of any type and size, may be empty */};int msgsnd(int msqid, struct msgbuf *ptr, int length, int flag);

• Sends message to Queue with specified ID.• Parameter msqid specifies ID of existing Message Queue• Parameter ptr must point to any structure with positive long first field.• Parameter length specifies real size of message data in pointed structure (excluding 1st field)• Parameter flag could be 0 or IPC_NOWAIT.• Without IPC_NOWAIT flag, the system call blocks, when Message Queue has no room for the new message

(occurs if too many messages in Queue or system-wide)• Returns 0 on success, -1 on error (errno specifies the error)

Page 38: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-38© D.Zinchin [[email protected]]

Receive Message from Message Queue#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>

int msgrcv(int msqid, struct msgbuf *ptr, int length, long msgtype, int flags);

• Receives message from Queue with specified ID.• Parameter msqid specifies ID of existing Message Queue• Parameter ptr points to buffer for message storage.• Parameter length specifies maximal length of message data to be received. • Parameter msgtype:

0 - receive message of any type

>0 - receive message of specific msgtype

<0 - receive message with lowest type that <=abs(msgtype)• Parameter flag could have bits:

MSG_NOERROR - no error if message data exceeds specified length (data is truncated)

IPC_NOWAIT - non-blocking mode• If IPC_NOWAIT flag is not specified, the system call blocks if Message of specified msgtype does not exist

System call unblocks in following cases:

- message appeared in Queue

- Queue removed

- signal interrupt• Returns number of bytes stored into the buffer ptr, -1 on error (errno specifies the error)

Page 39: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-39© D.Zinchin [[email protected]]

Message Queue usage Scenariosin Client – Server Model

1) Server and Client use separate Message Queues

2) Server and Client use the same Message Queue with different Message types

3) Multiplexing of messages for Server and number of Clients, using different

Message types for different Clients in the same Queue

Example:

Message Multiplexing for 1 Server and 3 Clients

4) Prioritizing of Messages by Message type (use msgrcv() with msgtype <0)

message queue

server

client 1pid = 123

client 2pid = 456

client 3pid = 789

type = 1 type = 123 type = 1 type = 789

type = 1 type = 456

type = 1 type = 123 or 456 or 789

Page 40: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-40© D.Zinchin [[email protected]]

Semaphores are synchronization construct.

Designed by E. W. Dijkstra in the late 1960s.

Original model :

Railroad with single track section, guarded by semaphore. Before entering the track train must wait for

permitted (unlocked) state of semaphore. The semaphore changes its state when train enters the track (locked)

and when the train leaves the track (unlocked).

In programming:

Semaphore used to provide resource access synchronization between different processes.

Simplified Model

Legend:

semaphore=0 – resource locked,

semaphore=1 – resource unlocked.

Problems:

1) Critical region between Testing of “semaphore”

value and its Setting (decrement) leads to Race Condition.

2) Waiting process continues to use CPU

/* wait for resource to be unlocked*/while(semaphore<1) ; /* lock resource */semaphore--;…/* unlock resource */semaphore++;

System V Semaphore is not a single value, but set of nonnegative integer counters.

Kernel provides group of operations on semaphore, executed in “atomic” mode.

System V Semaphore

What is Semaphore

Page 41: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-41© D.Zinchin [[email protected]]

Semaphore Access

#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>

int semget(key_t key, int nSems, int flags);

• Creates new Semaphore set with nSems semaphores if:

- key = IPC_PRIVATE or

- key does not refer to existing Semaphore set

and IPC_CREAT flag specified• If Semaphore set was created or already exist, returns its ID.• Returns -1 in case of error, errno specifies the error.

In combination with IPC_CREAT – return an error, if set already existsIPC_EXCL

Create if does not existIPC_CREAT

Write by others0002

Read by others0004

PermissionsWrite by group0020

AccessRead by group0040

Write by owner0200

Read by owner0400

flags:

createerrorperms | IPC_CREAT | IPC_EXCL

createopenperms | IPC_CREAT

erroropenperms

No

Queue existsFlags

Combination: Yes

#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>

int semctl(int semid, int semNum, int cmd, …);

• Performs control operations on specified element in Semaphore set.

• To remove Semaphore set, used in following form:

semctl(msqid, 0, IPC_RMID);

• Returns 0 in success, -1 in case of error (errno specifies the error)

• (Other possible operations will be described later)

Page 42: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-42© D.Zinchin [[email protected]]

Semaphore Operations#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>

struct sembuf { ushort_t sem_num; /* semaphore number, beginning from 0 */ short sem_op; /* semaphore operation */ short sem_flg; /* operation flags */

}; int semop(int semid, struct sembuf * pOps, size_t nOps);

• Performs set of operations on Semaphore set with specified ID.• Parameter pOps is array of structures, one structure per operation.• Parameter nOps is array length.• Operation type is specified by sem_op field and has the following meaning:

sem_op > 0 : Semaphore[sem_num] += sem_op;

sem_op = 0 : wait while (Semaphore[sem_num] != 0);

sem_op < 0 : wait while (Semaphore[sem_num] < abs(sem_op)); Semaphore[sem_num] += sem_op;

• Field sem_flg could contain the following bit flags:

IPC_NOWAIT – operation to be performed in non-blocking mode

SEM_UNDO – individual operation in the array to be rolled back when the process exits • All set of operations, specified by array, is performed by Kernel as one impartible “atomic” operation.

The execution rule is “all or nothing”: if one of operation fails, all other operations in array are not performed.• The system call semop() blocks (unless the IPC_NOWAIT flag is set), and remains blocked until:

- the semaphore operations can all finish, so the call succeeds, - the process receives a signal, or - the semaphore set is removed.

• Returns 0 on success, -1 on error (errno specifies the error).

Page 43: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-43© D.Zinchin [[email protected]]

Example 1: Binary Semaphore as Signal Emulation Device

/*-- SERVER ---*/…int semID;semID=semget(THE_SEM_KEY, 2, 0666|IPC_CREAT); /* initially Semaphore[i] = 0 */semSigWait(semID, SEM_SERVER);

semSigSend(semID, SEM_CLIENT);

/*--- CLIENT ---*/…int semID;semID=semget(THE_SEM_KEY, 0, 0666);…semSigSend(semID, SEM_SERVER);semSigWait(semID, SEM_CLIENT);

Note:

“Eternal” waiting for never arrived “signal” could be avoided by replacing semop() system call with:

int semtimedop(int semid, struct sembuf * pOps,size_t nOps,struct timespec *timeout);

where:

#include “time.h”struct timespec { time_t tv_sec; /* seconds */ long tv_nsec;/*nanoseconds*/ };

The Scenario:• We need stateful device with operations: non-blocking “send signal”, and impartible blocking “wait for signal”.• To avoid race condition (signal loss), the initial state of the device would be “waiting for signal” . The Solution:• “Waiting” state will correspond to 0 value of semaphore, “signal sending” will correspond to ++ operation.

/*--- COMMON ---*/#define THE_SEM_KEY 1357#define SEM_CLIENT 0#define SEM_SERVER 1…int semSigSend(int semID, int semN) /* Semaphore[semN]+=1 */{ struct sembuf pOps[1]; pOps[0].sem_num = semN; pOps[0].sem_op = 1; pOps[0].sem_flg = 0; return semop(semID,pOps,1);}

int semSigWait(int semID, int semN) /* wait while (Semaphore[semN] < 1); */{ /* Semaphore[semN] --; // reset to 0 */ struct sembuf pOps[1]; pOps[0].sem_num = semN; pOps[0].sem_op = -1; pOps[0].sem_flg = 0; return semop(semID,pOps,1);}

Page 44: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-44© D.Zinchin [[email protected]]

Example 2: Binary Semaphore as Resource Locking DeviceThe Scenario:• We need device with 2 states (locked / unlocked) and operations “lock” and “unlock”.• Operation “lock” would be impartible, working in blocking mode, if device already “lock”-ed by another process.• Initial state of device to be “unlocked” to avoid deadlocking forever in case of initialization failure.The Solution: “Unlocked” state will correspond to 0 value of semaphore, “locked” state will correspond to value 1.

int semLock(int semID, int semN) /* wait while (Semaphore[semN] !=0 ); */{ /* Semaphore[semN]++; // i.e. = 1 */ struct sembuf pOps[2]; pOps[0].sem_num = semN; pOps[0].sem_op = 0; pOps[0].sem_flg = 0; /* IPC_NOWAIT to be used for non-blocking mode*/ pOps[1].sem_num = semN; pOps[1].sem_op = 1; pOps[1].sem_flg = SEM_UNDO; /* roll-back the operation on process exit */ return semop(semID, pOps, 2);}

int semUnlock(int semID, int semN) /* Semaphore[semN] --; // i.e. = 0 */{ /* would not require blocking */ struct sembuf pOps[1]; pOps[0].sem_num = semN; pOps[0].sem_op = -1; pOps[0].sem_flg = IPC_NOWAIT|SEM_UNDO; /* no block + roll-back on exit */ return semop(semID, pOps, 1);}

Note:

Locking “forever” by unexpectedly terminated process is avoided by usage of SEM_UNDO flag

Page 45: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-45© D.Zinchin [[email protected]]

Control Operations on Semaphore Set#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>

union semun { int val; /* for SETVAL */ struct semid_ds *buf; /* for IPC_STAT, IPC_SET */ unsigned short *array; /* for GETALL, SETALL */};int semctl (int semid, int semNum, int cmd, … /*union semun arg*/);

• Performs control operations on Semaphore set• Parameter cmd could have the following values: IPC_STAT - copy Semaphore set info to arg.buf IPC_SET - update Semaphore set permissions and ownership from arg.buf GETALL,SETALL - get / set semaphore semval values using arg.array (on set adjustment roll-back values are cleared in all processes, blocked processes are unblocked) SETVAL - set semval value of semaphore number semNum to be equal val. (adjustment roll-back value is cleared in all processes, blocked processes are unblocked) GETVAL,GETPID,GETNCNT, GETZCNT - return corresponded values for semaphore number semNum IPC_RMID - remove Semaphore set (unblocking any blocked processes)• Returns actual value for getter methods, 0 on success for others, -1 on error (errno specifies the error)

Example: Unlock method implementationint semUnlock(int semID, int semN) { union semun {int val; struct semid_ds *buff; ushort *array;} arg; arg.val=0; return semctl(semID, semN, SETVAL, arg);}

sem_ctime

sem_otime

sem_nsems

sem_base

sem_perm structure

struct semid_ds

semzcnt

semncnt

sempid

semval

struct sem

time of last semop -

time of last change -

- semaphore value

- pid of last operation

- # awaiting value > x

- # awaiting value = 0

semid

kernel

Page 46: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-46© D.Zinchin [[email protected]]

Example: Shared Memory - based Client-Server Modelwith Semaphore Synchronization

ServerClient Data Buffer

kernel

SEM_SER_LOCKSEM_SER_SIGSEM_CLI_SIGSEM_CLI_LOCK

Semaphore Set

Work with Client:

semSigWait();

Work with Client:semSigSend();

Start: semLock();Stop: semUnlock();

Work with Server:semSigWait();

Work with Server:semSigSend();

Data Length

Shared Memory

Start: semTryLock();Stop: semUnlock();

Page 47: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-47© D.Zinchin [[email protected]]

Safe Usage of Semaphore

The Problem:

After unexpected termination (for example, with SIGKILL) of process, responsible for Semaphore set deletion,

this unused set could remain until system reboot.

The Proposed Solution:

One of possible solutions (See [1]) is to provide user-defined locking utilities, maintaining the Semaphore

set of 3 semaphores instead of single semaphore, as follows:

• The First semaphore is used for lock/unlock operations (as in previous examples)

• The Second semaphore is initialized to sufficiently big value and then used as counter of processes, currently

using the Semaphore set. For this purpose user-defiled methods open/close provide decrementing and

incrementing of this counter correspondently.

• Knowing the number of processes, which use the Semaphore set, this set may be deleted by the last process,

closing it.

• The Third semaphore is used to avoid race condition during Semaphore set (re)creation / closing.

Note:

The problem with unexpectedly terminated last process, responsible to delete Semaphore set, still exists.

But, with implementation described above, it could occur with significantly lower probability.

Page 48: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-48© D.Zinchin [[email protected]]

POSIX SemaphoresPOSIX provides it’s own standard of Semaphore as Inter-Process or Inter-Thread synchronization device.POSIX Semaphore is single non-negative integer counter with only 2 possible operations: • Post – Semaphore+=1 (analog of System 5 sem_op=1)• Wait – wait while (Semaphore == 0); Semaphore -=1; (analog of System 5 sem_op=-1)POSIX defines 2 forms of Semaphores: Named and Unnamed.

#include <semaphore.h> sem_t *sem_open(const char *name, int oflag, …/*mode_t permissions, unsigned int value*/);

• Creates new or opens already existing Named Semaphore, identified by Full Path name , beginning from “/”.• Parameter oflag could be combined from binary flags O_CREAT, O_EXCL (see call open() ).• For newly-created Semaphore octal permissions and initial value are required.• Returns pointer to Semaphore on success, SEM_FAILED constant on failure (errno specifies error).

int sem_close(sem_t *sem);

• Closes the Named Semaphore. • Returns 0 on success, -1 on failure.

int sem_unlink(const char *name);

• Removes Named Semaphore. The name is removed immediatelly. Semaphore object is destroyed when sem_close()-d by all processes.• Returns 0 on success, -1 on failure.

int sem_init(sem_t *sem, int pshared, unsigned int value);

• Initializes new Unnamed Semaphore in address sem with initial value for Inter-Process (pshared =1, sem points to shared memory) or for Inter-Thread (pshared =0) synchronization.• Returns 0 on success, -1 on failure.

int sem_destroy(sem_t *sem);

Unnamed Semaphore – memory-based semaphore allocated in memory shared by multiple processes or threads.

• Destroys the Unnamed Semaphore pointed by sem. • Returns 0 on success, -1 on failure.

Named Semaphore – identified by pathname, visible by multiple processes

Semaphore Operations: Post and Wait

int sem_post(sem_t *sem);

• Increments (unlocks) the Semaphore sem.• Returns 0 on success, -1 on failure.

int sem_wait(sem_t *sem);

• Waits until Value of Semaphore sem becomes positive, then decrements (locks) the semaphore.• Returns 0 on success, -1 on failure.

Page 49: UNIX Process

Introduction to Network Programming in UNIX & LINUX 2-49© D.Zinchin [[email protected]]

BSD Shared Memory#include <unistd.h> #include <sys/mman.h>

void *mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);

• Maps a file of specified length, pointed by open descriptor fd,

into the current process memory, pointed by start (may be NULL), beginning from specified offset.

The memory divided into pages (4K). Each page loaded from file once, when was accessed at first time.• Parameter prot specifies the permissions (protection mode - what could be done with segment),

and could have the following values:

PROT_EXEC, PROT_READ, PROT_WRITE, PROT_NONE • Parameter flags describes the memory sharing modes and visibility:

MAP_FIXED, MAP_SHARED, MAP_PRIVATE, MAP_ANONYMOUS

When map is shared, it could be attached by multiple processes in the same time.• Returns pointer to mapped memory or -1 in case of problem (errno specifies the error)

int msync(const void *start, size_t length, int flags);

• Synchronizes memory with source file. When shared segment is modified, the changes do not appear in the file until msync() is called.

int mprotect(const void *addr, size_t len, int prot);

• Modifies the protection mode of the shared memory

int munmap(void *start, size_t length);

• Unmaps the attached segment.

Example of mmap() usage:int fd; char* pBuff; fd = open("/dev/zero", O_RDWR)); pBuff = mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); (void) close(fd);