Вы находитесь на странице: 1из 317

(IPC Interprocess Communication).

, , ,
, . :
1. , . ,
, .
2. , IPC.
Unix , .
3. , , .
IPC, .
: , ,
.
.
,
.
IPC:
1. (, FIFO, ).
2. ( , , -, , ).
3. ( ).
4. (, Sun RPC).
, .
TCP/IP; ([24]).
, IPC, ,
. IPC, ,
, , .
. ,
, IPC.
:
UNIX Network Programming, 1, 1998 [24];
Advanced Programming in the UNIX Environment, 1992 [21];
TCP/IP Illustrated, 1, 1994 [22];
TCP/IP Illustrated, 2, (Gary Wright),1995, [27];
TCP/IP Illustrated, 3, 1996 [23].
, IPC , Network Programming. , IPC
. UNIX Network Programming 1990 ,
(IPC).


3 18 UNIX Network Programming 1990 . ,
. :
System V IPC ( , , ) Posix,
IPC. Posix 1.7.
Posix, System V.
Posix: , , -.
.
Posix (Pthreads), (
) .
Posix.
IPC ,
- Posix ( ).
. , Posix , .
, ( , , ,
). - .
RPC Sun RPC. Solaris,
RPC, . ,
.

?
IPC . :
;
;
;
.
, .
, 2 Posix IPC, 3 System V IPC, 12
( Posix, System V). 1, 1.6,
-. , Posix IPC, , System V IPC.
. , , .
.
.


( ). IPC
. .
, .
.

, . ,
. , , , .
, . (135 ). ,
, . , , , ,
- , , , , , , -, , , , ,
. , . , , .
, , .
: , , , , , , , , ,
.
GSquared. , , NOAO, ,
. , , Digital Equipment Corp.
Alpha, . .
Red Hat Software ( Red Hat Linux), RS/6000 AIX.
Prentice Hall , ,
.


- PostScript. groff (
) SparcStation Solaris 2.6. ( groff ). 138 897 vi,
72 gpic ( ), 35 gtbl, (
awk, ) . loom, GNU indent
8046 .
, .
W. Richard Stevens Tucson, Arizona July 1998
rstevens@kohala.com http://www.kohala.com/~rstevens


, , comp@piter.com ( , ).
!
, , http://www.piter.com/download.
web- http://www.piter.com .

1
IPC UNIX
1
Unix
1.1.
IPC interprocess communication, .
- . ,
, , , .
Unix 30 :
(pipes 4) , (
). ,
(ancestor), (named pipes), FIFO ( 4).
System V (System V message queues 4) System V 80-.
, .
System V, Unix, , System V, .

Unix , . , ,
, - (forks). fork
, . . ,
.
( ) fork, IPC .
IPC . 1.4. , Unix init,
(bootstrapping). (login shell)
, . 9 [24] .

, ,
.
Posix (Posix message queues 5) Posix (1003.1b-1993,
1.7). - .
(remote procedure calls RPC, 5) 80-
() , ().
. (
) , RPC
.
Unix:
, (
), , 9.8,
(record locking 9) Unix 80- Posix.1 1988.
System V (System V semaphores 11) (System V shared
memory 14) System V ( 80-). IPC Unix.
Posix (Posix semaphores 10) Posix (Posix shared memory 13) Posix
(1003.1b-1993, Posix).
(mutex, conditional variable 7) ,
Posix (Posix threads, Pthreads 1003.1-1995). ,
.
- (read-write locks 8) .
Posix, , , .

1.2. ,
Unix ,
. . 1.1.

. 1.1.
1. , .
( read, write, lseek, write, lseek ).
, , , ,
.
2. , . ,
System V. .
3. , .
, . , , ,
, .
, .
. .

Unix ,
. Posix.1, Pthreads, 1995 .
( ).
. , , IPC,
IPC .
. ,
, , , -
. ,
Unix, read. ,
, , , .
- .
Pthread,
.
1.3. IPC
(persistence) IPC . . 1.2
, .

. 1.2. IPC
1. IPC, (process-persistent), , ,
. (pipes, FIFO).
2. IPC, (kernel-persistent), .
System V, . Posix,
, .
3. IPC, (filesystem-persistent), , .
. Posix, ,
( ).
IPC, . , (pipe)
, , , , ,
, , . , FIFO ,
, , , ,
.

. 1.1 IPC.

1.1. IPC

IPC
(pipe)
(FIFO)
Posix (mutex)
Posix (condition variable)
- Posix (lock)
fcntl
Posix (message queue)
Posix (named semaphore)
Posix (memory-based semaphore)
Posix (shared memory)
System V
System V
System V
TCP (TCP socket)
UDP (UDP socket)
Unix (Unix domain socket)

, IPC , . ,
IPC Posix . ,
, , IPC . IPC ,
, . , , ,
IPC, .
1.4.
- IPC , IPC ,
( server) , ( client)
.
(pipes) ( ),
FIFO , ( FIFO
). IPC, ,
(naming conventions). IPC (name space).
, IPC, ,
.
. 1.2 IPC.
1.2. IPC

IPC

FIFO

Posix

Posix
Posix
fcntl
Posix

System V
System V

System V
(doors)

(RPC) Sun
TCP
UDP
Unix



( )
(pathname)
( )


pthread_mutex_t

pthread_cond_t

pthread_rwlock_t

IPC System
V
IPC System
V
IPC System
V

(handle) RPC

IP- TCP
IP- TCP

( )
( )

Posix- IPC
key_t
key_t
key_t

Posix.1
1996

Unix
98

.1g
.1g
.1g

(domain socket)
, IPC Posix.1 1996 Unix 98.
1.7. , [24].
, (Application Program Interface API) Posix.1g
Posix.1.
Posix. 1 , . . 1.3
, Posix.1 Unix 98. (mandatory), (not defined)
( optional). (, _POSIX_THREADS),
( ), . , Unix 98 Posix.1
.

1.3. IPC

IPC

FIFO
Posix
Posix


- Posix
fcntl
Posix
Posix
Posix
System V
System V
System V
(doors)
Sun
mmap
(realtime
signals)

Posix.1 1996

_POSIX_THREADS
_POSIX_THREADS
_POSIX_THREADS_PROCESS_SHARED

Unix 98

(He )

_POSIX_MESSAGE_PASSING
_POSIX_SEMAPHORES_
_POSIX_SHARED_MEMORY_OBJECTS
(He )
(He )
(He )
(He )
(He )
_POSIX_MAPPED_FILES
POSIX_SHARED_MEMORY_OBJECTS
_POSIX_REALTIME_SIGNALS

_XOPEN_REALTIME
_XOPEN_REALTIME
_XOPEN_REALTIME

( )
( )

begun

_XOPEN_REALTIME

1.5. fork, exec exit IPC


fork, exec _exit IPC, (
exit). . 1.4.
, . -, fork
(multithreaded process) ( , ,
, ). 6.1 [3] . ,
, ,
. -, IPC System V . 6.6 11.1 14.1 ,
, , IPC, . ,
, .
1.4. fork, exec _exit IPC

IPC

fork

exec

,

FD_CLOEXEC


Posix



System V

,
,


,



Posix

- ,
,
Posix
,

_exit

,
FIFO


,
,


,
,


Posix,

Posix
System V



,
,
,





semadj
semadj
0



,
,


semadj



,
fcntl
, ,

(unmap)




Posix



System V



(doors)



,

,



FD_CLOEXEC

1.6. : -
.
, , - (wrapper functions),
, .
- , , ,

Sem_post(ptr);
- 1.1[1]

1.1. - sem_post
// lib/wrapunix.c
387 void
388 Sem_post(sem_t *sem)
389 {
390 if (sem_post(sem) == 1)
391
err_sys("sem_post error");
392 }
, , : -.
, . - ,
.
, , (, sem_post),
- (, Sem_post). , .

. . , ,
. ,
, .
. wrapunix.c lib.
(. ), . ,
.
, - , 7,
, (thread functions) Unix errno ;
. , pthread
, , errno ,
err_sys ( .4). , (comma)
errno err_sys , :

int n;
if
((n
=
pthread_mutex_lock(&ndone_mutex))!=0)
err_sys("pthread_mutex_lock error");

errno=n,

, .
,

Pthread_mutex_lock(&ndone_mutex);
-, 1.2.

1.2. pthread_mutex_lock
//lib/wrappthread.c

125
126
127
128
129
130
131
132
133

void
Pthread_mutex_lock(pthread_mutex_t *mptr)
{
int n;
if ((n=pthread_mutex_lock(mptr))==0)
return;
errno=n;
err_sys("pthread_mutex_lock error");
}

, , ,
- ( ) .
. :
([10, . 182]), _ . .
, - .
: , , ,
close pthread_ mutex_lock.
-,
, . ,
(. ).
errn o
Unix errno , ;
1. err_sys (, Resource temporarily
unavailable , errno EAGAIN).
errno .
. , ,
. 0.
errno.
, , .
D_REENTRANT D_POSIX_C_SOURCE=199506L . errno ,
, _REENTRANT. errno, .
mq_send EMSGSIZE, ,
( 1) errno .
1.7. Un ix
Unix Posix The Open Group.
Posix
Posix Portable Operating System Interface, .
, , (Institute for Electrical and Electronics
Engineers IEEE). Posix ISO (International Organization for Standardization,
) IEC (International Electrotechnical Commission, ), ISO/IEC.
Posix .
IEEE 1003.1-1988 (317 ) Posix. Unix-
: ( fork, exec, ), ( ,
), ( -), , ( ), tar
cpio.

Posix IEEEIX 1986 . Posix (Richard


Stallman).
IE 1003.1-1990 (356 ). ISO/IEC 9945-1:1990.
1988 1990 . : Part 1: System Application Program Interface (API) [C
Language] ( 1: (API) [ ]), , (API)
.
IEEE 1003.2-1992 1300 , Part 2: Shell and Utilities ( 2:
). ( Bourne shell Unix System V) (,
awk basename vi ). Posix. 2.
IEEE 1003.1b-1993 (590 ) IEEE P1003.4. 1003.1-1990
, 1003.4: , -, ,
, (scheduling), , .
IEEE 1003.1, 1996 [8] (743 ), 1003.1-1990 ( API), 1003.1b-1993 ( ),
1003.1-1995 (Pthreads Posix) 1003.1i-1995 ( 1003.1b). ISO/IEC 9945-1: 1996.
, (
), , . Posix.1.

743 , Rationale and Notes ( ).


, .
, .
, IEEE . , ,
[8]. , ,
( Pthreads), API .
, , - Posix. 8.
IEEE 1003.1, P1003.1g, ( XTI),
.
Posix.1 1996 , ISO/IEC 9945 :
1. (API) ( ).
2. .
3. ( ).
1 2 , Posix.1 Posix.2.
Posix , , , .
http://www.pasc.org/standing/sd11.html.

The Open Group


The Open Group ( ) 1996 X/Open Company ( 1984 ) Open Software Foundation
(OSF, 1988 ). ,
. :
1989 /Open 3- X/Open Portability Guide ( ) XPG3.
1992 (Issue 4), 1994 (Issue 4, Version 2).
Spec 1170, 1170 (926), (70) (174).
: X/Open Single Unix Specification ( Unix) Unix 95.
1997 Unix.
Unix 98, . Unix 98 1170 1434,
3030, CDE (Common Desktop Environment ), ,
, X Window System Motif. [9].
http://www.UNIX-systems.org/version2.

Unix .
Un ix
Unix, , - Posix.1 Posix.2.
-, Posix (, 1993 1996)
, .
Unix BSD, System V, ,
Posix. ,
Posix .
Solaris 2.6 Digital Unix 4.0B. ,
( 1997 1998 ) System V IPC, Posix IPC Posix (Pthreads).
1.8. IPC
() :
1. : -, ,
.
2. -: () ,
() .
3. : .
.
,
.
1.5, 1.6 1.7 , .
.
1.9.
Unix. ,
. IPC .
1. (, FIFO, ).
2. ( , , -, ).
3. ( ).
4. ( Solaris, RPC Sun).
, .
IPC , ,
. IPC .
IPC , IPC ,
. (, , , -),
( FIFO), , 2 IPC Posix,
, 3 ( IPC System V). IPC ,
.
, , -, 1.6, , ,
, . - .
IEEE Posix Posix.1, Unix, Posix.2, , ,
. Posix ( )
, The Open Group (Unix 98).
1.5. -

4.1
4.5
4.6
4.7
4.10
4.12
6.7
6.12
6.16
15.15


popen cat
FIFO
FIFO
FIFO

FIFO:
System V
System V
System V ;

8

1.6. -

7.1
, ,
7.5
, ,

10.8
Posix, ,
10.11
Posix , ,
10.12
Posix , ,
10.15
Posix , ,
10.18
Posix , , :

1.7.

9.1
9.3
9.9
10.10
12.2
12.3
12.4
12.5
13.6
.19
.22
.23
.25
.28
.29
.33

,
, fcntl
, open
, Posix
mmap, Posix
mmap, Posix
4.4BSD, Posix
SVR4 /dev/zero, Posix
Posix, Posix
:
: -
: Posix
: Posix
: System V
: fcntl
:

1. 1.1 , . (,
), ?
2. , errno.
3. . 1.3 , Unix-.
2
Posix IPC
2.1.
IPC Posix IPC, ,
Posix:
Posix ( 5);
Posix ( 10);
Posix ( 13).
IPC , .
, , , IPC,
.
, IPC, . 2.1.
2.1. Posix IPC


IPC

mq_open mq_close
mq_unlink
mq_getattr mq_setattr
mq_send mq_receive
mq_notify

sem_open sem_close sem_unlink sem_init


sem_destroy
sem_wait sem_trywait sem_post
sem_getvalue


shm_open
shm_unlink
ftruncate fstat
mmap munmap

2.2. IPC
. 1.2 , IPC Posix (), . IPC
: mq_open, sem_open shm_open,
. Posix.1 IPC :
( ,
0).

(/), .
.
.
, (/) . ,
, , .
Solaris 2.6 . , ,
/tmp, .MQ. , mq_open /queue.1234,
/tmp/.MQDqueue.1234, /tmp/.MQLqueue.1234 /tmp/.MQPqueue.1234. Digital Unix 4.0B
.
:
. , /tmp.1234 Posix Solaris, Digital Unix
, . /tmp/test.1234, Digital Unix
, , ( /tmp
, Unix), Solaris .
#define,
.

, Unix
. , .
Posix .
Posix.1 :

S_TYPEISMQ(buf)
S_TYPEISSEM(buf)
S_TYPEISSHM(buf)
stat, fstat, lstat stat.
, IPC ( , )
stat . 0.

, , , IPC . ,
Solaris 2.6 0.
, , , S_IS, :
st_mode stat. , IPC, , S_TYPEIS.
px_ ipc_name
. px_ipc_name,
Posix IPC.

#include "unpipc.h"
char *px_ipc_name(const char *name);
/* , NULL */

, , .
unpipc.h ( B.1).
() . , , px_ipc_name("test1") /test1
Solaris 2.6 /tmp/test1 Digital Unix 4.0B. free.
PX_IPC_NAME, .
2.1[1] .

, snprintf.
sprintf, . snprintf
. , sprintf,
.
snprintf ANSI , , 9.
. snprintf ,
sprintf, snprinft .

2.1. px_ipc_name .
//lib/px_ipc_name.c
1 #include "unpipc.h"
2 char *
3 px_ipc_name(const char *name)
4 {
5
char *dir, *dst, *slash;
6
if ((dst = malloc(_)) == NULL)
7
return(NULL);
8 /*
9
if ((dir = getenv("PX IPC_NAME")) == NULL) {
10 #ifdef POSIX_IPC_PREFIX
11
dir = POSIX_IPC_PREFIX; /* "config.h" */
12 #else
13
dir = "/tmp/"; /* */
14 #endif
15 }
16 /* '/' */
17 slash = (dir[strlen(dir) 1] == '/') ? "" : "/";

*/

10

18 snprintf(dst, PATH_MAX, "%s%s%s", dir, slash, name);


19 return(dst); /* free() */
20 }
2.3. IPC
, IPC: mq_open, sem_open shm_open, oflag
. open.
, , . 2.2.

2.2. , IPC




,


(truncate)

mq_open
sem_open
_RDONLY
_WRONLY
_RDWR
_CREAT
_CREAT
_EXCL
_EXCL
_NONBLOCK

shm_open
_RDONLY
_RDWR
_CREAT
_EXCL
O_TRUNC

: , , .
, (
). , .
. 2.2 .
O_CREAT , , (. O_EXCL,
).
,
, .
. 2.3.

2.3. IPC

S_IRUSR
S_IWUSR
S_IRGRP
S_IWGRP
S_IROTH
S_IWOTH

.
(. 83-85 [21]) umask.
, ,
, (effective) .
,
.
( . 77-78 [21] ).

Posix IPC. ,
open, ,
, , IPC , IPC .
O_EXCL O_CREAT, ,
, . O_CREAT | O_EXCL, EEXIST.
, ( )
. System V IPC, 3.4.
O_NONBLOCK .
. , mq_send mq_receive 5.4.
O_TRUNC ,
0.
. 2.1 IPC.
, 2.4. . 2.1 . 2.4.

11

. 2.1. IPC
, . 2.4, O_CREAT, ,
.
2.4. IPC

oflag


, errno=ENOENT
OK,
O_CREAT
OK, OK,
O_CREAT|O_EXCL
OK, , errno=EEXIST
2.4. IPC
, mq_open, sem_open shm_open,
, oflag O_CREAT. . 2.3, IPC
(permissions), Unix.
, ( ,
O_CREAT O_CREAT O_EXCL ) :
1. , IPC .
2. (O_RDONLY, O_WRONLY, O_RDWR).
3. ,
( ).
Unix :
1. 0 ( ), .
2. IPC:
, , .
, , , .
, (user-write).
3.
IPC: , , .
4. , , .
. , IPC ( 2),
(). . ,
IPC, ,
.

. 2.2, sem_open O_RDONLY, O_WRONLY, O_RDWR. 10.2, , ,


Unix O_RDWR, .
2.5.
Posix IPC , .
, .
px_ipc_name. IPC ,
open. IPC , S_xxx, open (. 2.3).
IPC , .

1. (set-user-ID, SUID) (set-group-ID) ( 4.4


[21]) , Posix IPC, , 2.4?
2. IPC, , IPC
?
3

12

System V IPC
3.1.
IPC System V IPC, ,
System V:
System V ( 6);
System V ( 11);
System V ( 14).
System V IPC : Unix System V. : ,
; . IPC
.
. 3.1.

3.1. System V IPC



msgget
msgctl
IPC
msgsnd msgrcv


semget
semctl
semop

shmget
shmctl
shmat shmdt

System V IPC . [16] :


, 70- Bell Laboratories ,
, Unix, . Columbus Unix, CB Unix.

. System V IPC Unix System V. 1983 .
3.2. key_t ftok
. 1.2 , System V IPC key_t. key_t
( 32-). ftok.
ftok key_t ( IPC IPC
key):

#include
key_t ftok(const char *pathname, int id);
// IPC 1
8 IPC.
, , IPC,
IPC, - . , ,
- . IPC, ,
, 1. IPC (, ),
: , 1 2. , ftok
IPC.
ftok stat, :
, pathname ( st_dev stat);
(i-node) ( st_ino stat);
8 ( ).
32- . ,
, ( ,
, IPC) (. 3.5).

, IPC_PRIVATE ( 3.4) .
, ftok 1. , ,
, , ,
, , , , ftok .

3.1 , stat ftok,


st_dev st_ino stat IPC. , ,
IPC 0x57.

3.1 [1] .
IPC
//svipc/ftok.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5
struct stat stat;
6
if (argc != 2)
7
err_quit("usage: ftok ");
8
Stat(argv[1], &stat);
9
printf("st_dev: &lx, st_ino: %Ix, key: %x\n",

13

10
(u_long) stat.st_dev, (u_long) stat.st_ino,
11
Ftok(argv[1], 0x57));
12 exit(0);
13 }
Solaris 2.6 :

solaris
st_dev:
solaris
st_dev:
solaris
st_dev:

%ftok /etc/system
800018, st_ino: 4a1b, key: 57018a1b
%ftok /usr/tmp
800015, st_ino: 10b78, key: 57015b78
%ftok /home/rstevens/Mail.out
80001f, st_ino: 3b03, key: 5702fb03

, 8 ; 12 st_dev 12 , , 12
st_ino 12 .
, , ,
. .

FreeBSD 8 , 8 st_dev 16 st_ino.


, , ftok, , st_dev st_ino .
, .
3.3. ipc_perm
IPC, , , .

struct ipc_perm {
uid_t uid; /* */
gid_t gid; /* */
uid_t cuid; /* */
gid_t cgid; /* */
mode_t mode; /* -*/
ulong_t seq; /* */
key_t key; /* IPC */
}
System V IPC .
ipc_perm .
3.4. IPC
getXXX, IPC (. 3.1), IPC ( key_t)
. , ftok,
. ( getXXX):
1. ftok, .
2. IPCPRIVATE, IPC.
. 3.1.

. 3.1. IPC
getXXX (. 3.1) oflag, - (
mode ipc_perm) IPC , IPC .
.
IPC_PRIVATE IPC.
, ftok IPC_PRIVATE.
IPC_CREAT oflag , .
, .
IPC_CREAT IPC_EXCL oflag ,
. , EEXIST ( IPC ).
IPC_CREAT IPC_EXCL IPC O_CREAT O_EXCL open.
IPC_EXCL IPC_CREAT .
IPC . 3.2. . 3.2
.

14

. 3.2. IPC
, . 3.2 IPC_CREAT IPC_EXCL ,
. IPC IPC_CREAT (
, ) IPC_CREAT | IPC_EXCL ( ). ,
, .

System V IPC Posix IPC I_ O_CREAT OEXCL,


open (. 2.2).
, System V IPC I_ ( )
oflag, open Posix IPC : oflag, _,
mode, .
3.2. IPC

oflag

IPC_CREAT
IPC CREAT|IPC_EXCL



, errno=ENOENT OK,

OK,
OK,

OK,
, errno=EEXIST

3.5. IPC
IPC getXXX, IPC_CREAT, ipc_perm
( 3.3):
1. oflag mode ipc_perm. . 3.3 IPC (
>>3 ).
2. cuid cgid , .
.
3. uid gid i_perm .
.
3.3. mode - IPC

()
0400

MSG_R

SEM_R

SHM_R

0200

MSG_W

SEM_A

SHM_W

15

0040
0020
0004
0002

MSG R>>3
MSG_W>>3
MSG_R>>6
MSG_W>>6

SEM_R>>3
SEM_A>>3
SEM_R>>6
SEM_A>>6

SHM_R>>3
SHM_W>>3
SHM_R>>6
SHM_W>>6

,
ctlXXX IPC IPC_SET. ctlXXX ( mode) IPC.

: MSG_R, MSG_W, SEM_R, SEM_A, SHM_R SHM_W, . 3.3.


, . Unix 98 . SEM_A alter ().
getXXX Unix. ,
.
Posix IPC IPC . Posix IPC_SET. Posix IPC
, chown.
- IPC, :
( getXXX) IPC:
1. IPC getXXX oflag,
. , mode ipc_perm ( .
3.2). , - mode ,
. , oflag msgget, . , ,
getXXX, . ,
: , .
, , getXXX .
, oflag, 0, IPC.
2. IPC , . ,
msgsnd, (
).
.
uid cuid IPC
mode IPC, . , ,
IPC (, ), , ,
.
gid cgid IPC
mode IPC, .
,
.
3.6.
ipc_perm ( 3.3) seq, .
, IPC . IPC ,
.

SVR4 . Unix 98 .
. -, ,
. ,
. 4 , .
. System V IPC
, .
IPC getXXX: msgget, semget, shmget. ,
, . ( )
, , msgget,
, . - , ,
, , (
) , .
( ),
1/50 ( 50 ).
IPC ,
, . ,
, IPC ,
. , 50 ,
0.
50. 100, 150 . . seq (ulong
. ipc_perm 3.3), , 85899346
(2/50 , 32-).
, ,
System V IPC . ,
.
, 3.2 , msgget.

3.2.

//svmsg/slot.c
1 #include
2 int
3 main(int argc, char **argv)
4 {

16

5
int i, msqid;
6
for (i=0;i<10;i++) {
7
msqid=Msgget(IPC_PRIVATE, SVMSG_MODE|IPC_CREAT);
8
printf("msqid = %d\n", msqid);
9
Msgctl(msqid, IPC_RMID, NULL);
10 }
11 exit(0);
12 }
msgget , a msgctl IPC_RMID .
SVMSG_MODE unpipc.h ( .1) System V.
:

solaris
msqid =
msqid =
msqid =
msqid =
msqid =
msqid =
msqid =
msqid =
msqid =
msqid =

%slot
0
50
100
150
200
250
300
350
400
450

, ,
.

solaris
msqid =
msqid =
msqid =
msqid =
msqid =
msqid =
msqid =
msqid =
msqid =
msqid =

% slot
500
550
600
650
700
750
800
850
900
950

3.7. ipcs ipcrm


System V IPC , ,
ls rm. , IPC, : ipcs,
System V IPC, ipcrm, System V, .
, IPC. (ipcrm)
. .

System V IPC Posix, Posix.2. Unix 98.


3.8.
System V IPC , . , ,
. . 6.2, 11.1
14.1. System V.

11.2 [1] 8 [6] , System V.


.
, , ,
(16- PDP-11). ,
, Unix.
. , 16-
, .
Solaris 2.6, , 20. , sysdef. ,
, ( ). ,
/etc/system . /etc/system :

set
set
set
set
set
set
set

msgsys:msginfo_msgseg
msgsys:msginfo_msgssz
msgsys:msginfo_msgtql
msgsys:msginfo_msgmap
msgsys:msginfo_msgmax
msgsys:msginfo_msgmnb
msgsys:msginfo_msgmni

=
=
=
=
=
=
=

set semsys:seminfo_semopm =

17

set
set
set
set
set
set
set
set

semsys:seminfo_semume
semsys:seminfo_semaem
semsys:seminfo_semmap
semsys:seminfo_semvmx
semsys:seminfo_semmsl
semsys:seminfo_semmni
semsys:seminfo_semmns
semsys:seminfo_semmnu

=
=
=
=
=
=
=
=

set
set
set
set

shmsys:shminfo_shmmin
shmsys:shminfo_shmseg
shmsys:shminfo_shmmax
shmsys:shminfo_shmmni

=
=
=
=

, . 6.2, 11.1 14.1.


Digital Unix 4.0B sysconfig .
, q. ipc. ,
IPC System V, :

alpha %
ipc:
msg-max
msg-mnb
msg-mni
msg-tql

/sbin/sysconfig q ipc
=
=
=
=

8192
16384
64
40

shm-max
shm-min
shm-mni
shm-seg

=
=
=
=

4194304
1
128
32

sem-mni = 16
sem-msl = 25
sem-opm = 10
sem-ume = 10
sem-vmx = 32767
sem-aem = 16384
num-of-sems = 60
, /etc/sysconfigtab.
sysconfigdb. .
3.9.
msgget, semget shmget IPC System V.
ftok. IPCPRIVATE. IPC
System V IPC , ,
IPC. ( ), .
, .
System V IPC ipc_perm, , ,
, . System V Posix IPC , IPC System V
( XXXctl IPC_STAT), Posix IPC
. Posix IPC , ,
.
System V IPC getXXX (IPC_CREAT IPC_EXCL) 9
.
, System V IPC .
, . ,
System V IPC , .

1. msgctl 6.5 3.2 , , seq


ipc_perm.
2. 3.2 , . ,
, ,
msgget .
3. 3.5 , getXXX System V IPC . ,
FIFO ( mkfif, 4.6) System V, 666 (
). (FIFO ). , umask
.
4. . : -
(, ) ftok IPC_PRIVATE?
5. 3.1 , IPC . find,
, . ?

18

6. sar (system activity reporter ),

sar m 5 6
, 5 6 .
2

4

4.1.
IPC Unix, 1973 (Third Edition [17]).
, ,
. Unix System III (1982) FIFO,
. , read write.

() ,
(. 15.8 13.7 [24]).
, .
, FIFO.
, -,
IPC, .
4.2. -
- . 4.1. 6
, FIFO System V.
() IPC. IPC
. , IPC.
. IPC .
, . .
. 4.1 IPC.

. 4.1. -
4.3.
Unix. pipe
() :

#include
int pipe(int fd[2]);
/* 0 . 1 :*/
: fd[0] fd[1], , .

Unix, SVR4, (full-duplex pipes).


. IPC socketpair, 14.3 [24].
Unix. ,
.
Posix.1 Unix 98 , .
(, FIFO) S_ISFIFO.
: st_mode stat ( ) (). stat
fstat. FIFO fstat, lstat stat.
. 4.2 .

. 4.2.

, (
5.12). ( ) : ,
fork, (. 4.3). , ,
, . , . 4.4.

19

. 4.3. fork

. 4.4.

who|sort|lp
Unix .
,
. . 4.5.

. 4.5.
(), .
.
IPC :
1. 1 (fd1[0] fd1[1]) 2 (fd2[0] fd2[1]).
2. fork.
3. 1 (fd1[0]).
4. 2 (fd2[1]).
5. 1 (fd1[1]).
6. 2 (fd2[0]).
, , 4.1. , . 4.6.

20

. 4.6.

, 4.2, . main fork


. , .
, ( ) . ,
. 4.7.

. 4.7. . 4.1
, . 4.7 , , ,
: .
4.1[1] main .

4.1. main ,
//pipe/mainpipe.c
1 #include "unpipc.h"
2 void client(int, int), server(int, int);
3 int
4 main(int argc, char **argv)
5 {
6
int pipe1[2], pipe2[2]:
7
pid_t childpid;
8
Pipe(pipe1); /* */
9
Pipe(pipe2);
10 if ((childpid = Fork()) == 0) { /* child */
11
Close(pipe1[1]);
12
Close(pipe2[0]);
13
server(pipe1[0], pipe2[1]);
14
exit(0);
15 }
16 /* */
17 Close(pipel[0]);
18 Close(pipe2[1]);
19 client(pipe2[0], pipel[1]);
20 Waitpid(childpid, NULL, 0); /* */
21 exit(0);
22 }

, fork
8-19 , . 4.6. client
( 4.2), server ( 4.3).

waitpid
20 - ( ) , exit .
-. - , , ,
. SIGCHLD,
. client
main, . waitpid
(). waitpid, , init,
SIGCHLD.
client 4.2.

21

4.2. client
-
//pipe/client.
1 #include "unpipc.h"
2 void
3 client(int readfd, int writefd)
4 {
5
size_t len;
6
ssize_t n;
7
char buff[MAXLINE];
8
/* */
9
Fgets(buff, MAXLINE, stdin);
10 len = strlen(buff); /* fgets() */
11 if (buff[Len-l] == ' \n' )
12
len--; /* fgets() */
13 /* IPC */
14 Write(writefd, buff, len);
15 /* , stdout */
16 while ((n = Read(readfd, buff, MAXLINE)) > 0)
17
Write(STDOUT_FILENO, buff, n);
18 }

8-14 ,
fgets.


15-17 , , . ,
, .
4.3 server.

4.3. server
//pipe/server.c
1 #include "unpipc.h"
2 void
3 server(int readfd, int writefd)
4 {
5
int fd;
6
ssize_t n;
7
char buff[MAXLINE+1];
8
/* IPC */
9
if ((n = Read(readfd, buff, MAXLINE)) == 0)
10
err_quit("end-of-file while reading pathname"):
11 buff[n] = '\0'; /* 0 */
12 if ((fd = open(buff, O_RDONLY)) < 0) {
13
/* 4error: must tell client */
14
snprintf(buff + n, sizeof(buff) n, ": can't open. %s\n".
15
strerror(errno)):
16
n = strlen(buff);

22

17
Write(writefd, buff, n);
18 } else {
19
/* */
20
while ( (n = Read(fd, buff, MAXLINE)) > 0)
21
Write(writefd, buff, n);
22
Close(fd);
23 }
24 }


8-11 0 (null-terminated).
, read , , (MAXLINE
).

,
12-17 .
errno strerror ( [24, . 690-691]
).


18-23 open .
:

solaris % mainpipe /etc/inet/ntp.conf ,


multicastclient 224.0.1.1
driftfile /etc/inet/ntp.drift
solaris % mainpipe /etc/shadow
a,
/etc/shadow: can't open. Permission denied
solaris % mainpipe /no/such/file

/no/such/file: can't open. No such file or directory
4.4.
, . Unix SVR4
pipe, socketpair. ?
, . 4.8.

. 4.8.
, . 4.9.
, , ( , ),
.

. 4.9. ()
, , .14. ,
. , ,
, .
. 4.10 .

. 4.10.

. , fd[1], fd[0],
, fd[0], fd[1].
4.4 .

4.4.

23

//pipe/fduplex.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5
int fd[2], n;
6
char c;
7
pid_t childpid;
8
Pipe(fd); /* (., SVR4) */
9
if ((childpid = Fork()) == 0) { /* child */
10
sleep(3):
11
if ((n = Read(fd[0], &c, 1)) != 1)
12
err_quit("child: read returned %d", n);
13
printf("child read %c\n", c):
14
Write(fd[0], "c", 1);
15
exit(0);
16 }
17 /* */
18 Write(fd[1], "p", 1);
19 if ((n = Read(fd[1], &c, 1)) != 1)
20
err_quit("parent: read returned %d", n):
21 printf("parent read %c\n", c);
22 exit(0);
23 }
, fork. ,
. , , .
read ,
.
Solaris 2.6, , :

solaris % fduplex
child read p
parent read
, . 4.10, .
. ( ).
Digital Unix 4.0B, ( SVR4
, ), , :

alpha % fduplex
read error: Bad file number
alpha % child read p
write error: Bad file number
, ,
( fd[l]) , , ( fd[0]). . 4.8.
read EBADF, , . write ,
.
4.5. popen pcl ose
- popen,
, :

#include
FILE *popen(const char *mmnd, const char *t);
/* FILE * , NULL
*/
int pclose(FILE *strm);
/* 1 */
command . sh ( Bourne shell),
, command, PATH.
. popen FILE,
type:
type r, , command ;
type w, command.
pclose - stream, popen,
, .

popen pclose 14.3 [21].

4.5 , popen ( Unix) cat.

24

4.5. - popen
//pipe/mainpopen.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5
size_t n;
6
char buff[MAXLINE], command[MAXLINE];
7
FILE *fp;
8
/* */
9
Fgets(buff, MAXLINE, stdin);
10 n = strlen(buff); /* fgets() */
11 if (buff[n-1] == '\n')
12
n--; /* fgets() */
13 snprintf(command, sizeof(command), "cat %s", buff);
14 fp = Popen(command, "r");
15 /* */
16 while(Fgets(buff, MAXLINE, fp) != NULL)
17
Fputs(buff, stdout);
18 Pclose(fp);
19 exit(0);
20 }
8-17 , 4.2. ,
popen. cat .
4.1
. cat, . , Solaris 2.6
, , :

solaris % cat/etc/shadow
cat: cannot open /etc/shadow
BSD/OS 3.1 :

bsdi % cat /etc/master.passwd


cat: /etc/master.passwd: cannot open [Permission denied]
, popen , fgets
(EOF). cat (stderr), popen
.
4.6. (FIFO)
, .
( ).
FIFO first in, first out , , .
Unix .
FIFO ,
FIFO.
FIFO mkfif:

#include
#include
int mkfifo(const char *thnme, mode_t md);
/* 0 , 1 */
pathname Unix , FIFO.
mode , open. . 2.3
, . FIFO.
mkfifo open, O_CREAT | O_EXCL. , FIFO
EEXIST, . , open mkfifo.
, , mkfifo, ,
EEXIST, , open.
mkfif FIFO. .
FIFO open,
- (, fopen). FIFO , .
, .
FIFO write , read ,
FIFO . lseek FIFO ESPIPE.

, 4.1, , FIFO .
client server ; main, 4.6.

25

4.6. main ,
//pipe/mainfifo.c
1 #include "unpipc.h"
2 #define FIFO1 "/tmp/fifo.1"
3 #define FIFO2 "/tmp/fifo.2"
4 void client(int, int), server(int. int);
5 int
6 main(int argc, char **argv)
7 {
8
int readfd, writefd;
9
pid_t childpid;
10 /* FIFO, OK */
11 if ((mkfifo(FIF01, FILE_MODE) < 0) && (errno != EEXIST))
12
err_sys("can't create %s", FIF01);
13 if ((mkfifo(FIF02, FILE_MODE) < 0) && (errno != EEXIST)) {
14
unlink(FIF01);
15
err_sys("can't create %s", FIF02);
16 }
17 if ((childpid = Fork()) == 0) { /* child */
18
readfd = Open(FIF01, O_RDONLY, 0);
19
writefd = Open(FIF02, O_WRONLY, 0);
20
server(readfd, writefd);
21
exit(0);
22 }
23 /* */
24 writefd = Open(FIF01, O_WRONLY, 0);
25 readfd = Open(FIF02, O_RDONLY, 0);
26 client(readfd, writefd);
27 waitpid(childpid, NULL, 0); /* */
28 Close(readfd):
29 Close(writefd);
30 Unlink(FIF01);
31 Unlink(FIF02);
32 exit(0);
33 }

FIFO
10-16 /tmp . - . FILE_MODE
unpi.h ( .1)

#define FILEMODE(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)


/* */
, .
(file mode creation mask) .
17-27 fork, server ( 4.3), client
( 4.2). , ,
, . . 4.11.

26

. 4.11. -,

, , :
pipe. FIFO mkfifo
open.
, . FIFO
unlink. , FIFO, : FIFO
, , , .
.
, FIFO, . , , 4.6:
open , . , FIFO ,
- . , open , ,
, , .
, (deadlock). .
:
4.6 . , .
4.7 -. 4.6, .
fif.h 4.8. FIFO, ,
.
4.9 -, 4.6, .
, , FIFO ,
.

4.7. main
//pipe/server_main.c
1 #include "fifo.h"
2 void server(int, int);
3 int
4 main(int argc, char **argv)
5 {
6
int readfd, writefd;
7
/* FIFO. OK, */
8
if ((mkfifo(FIF01, FILE_MODE) < 0) && (errno != EEXIST))
9
err_sys("can't create %s", FIF01);
10 if ((mkfifo(FIF02, FILE MODE) < 0) && (errno != EEXIST)) {
11
unlink(FIF01);
12
err_sys("can't create %s", FIF02);
13 }
14 readfd = Open(FIF01, O_RDONLY, 0);
15 writefd = Open(FIFO2, O_WRONLY, 0);
16 server(readfd, writefd);
17 exit(0);
18 }

4.8. fifo.h,
,
//pipe/fifo.h
1 #include "unpipc.h"

27

2 #define FIFO1 "/tmp/fifo.1"


3 #define FIFO2 "/tmp/fifo.2"

4.9. main
//pipe/client_main.c
1 #include "fifo.h"
2 void client(int, int);
3 int
4 main(int argc, char **argv)
5 {
6
int readfd, writefd;
7
writefd = Open(FIFO1, O_WRONLY, 0);
8
readfd = Open(FIFO2, O_RDONLY, 0);
9
client(readfd, writefd);
10 Close(readfd);
11 Close(writefd);
12 Unlink(FIFO1);
13 UnLink(FIFO2);
14 exit(0);
15 }

FIFO , , ,
unlink . ,
. IPC, System V, ,
, , .
:

% server_fifo &
. -: -, fork exec.
FIFO exec,
. .
4.7.
, , ,
. .
1. open O_NONBLOCK. , open 4.9 :

writefd = Open(FIFO1, O_WRONLY | O_NONBLOCK, 0);


2. , fcntl O_NONBLOCK. ,
open O_NONBLOCK . fcntl,
F_GETFL, (OR) O_NONBLOCK
F_SETFL:

int flags;
if ((flags = fcntl(fd, F_GETFL, 0)) < 0) err_sys("F_GETFL error");
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0) err_sys("F_SETFL error");
, , :

/* */
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) err_sys("F_SETFL error");
4.1 , ,
FIFO.

4.1. O_NONBLOCK

(open)
FIFO

(open)
FIFO

FIFO

(
)

FIFO , FIFO

O_NONBLOCK

28

(open)
FIFO

(open)
FIFO

(read)

FIFO

(read)

FIFO
(write)

FIFO
(write)

FIFO

FIFO

FIFO , FIFO


ENXIO

,
FIFO
FIFO


,

read 0 ( )
FIFO


EAGAIN

read 0
( )

(. )
(. )
FIFO


FIFO SIGPIPE


SIGPIPE

, FIFO.
, FIFO,
. , read , .
, write, PIPE_BUF (, Posix,
4.11), . ,
FIFO , ,
, . . PIPEBUF,
.

Posix.1 , PIPE_BUF 512. , ,


1024 (BSD/OS 3.1) 5120 (Solaris 2.6). 4.11 , .
O_NONBLOCK -a FIFO
PIPE_BUF. aoo FIFO ,
write , , poao FIFO.
PIPE_BUF, :
, .
poao FIFO ,
EAGAIN. O_NONBLOCK, ,
, . ,
.
PIPE_BUF, :
FIFO , ,
, write.
FIFO , EAGAIN.
FIFO, , SIGPIPE:
(catch) SIGPIPE, .
SIGPIPE , write
EPIPE.

SIGPIPE , , , ,
write. ( SIG_IGN) write
EPIPE. , write, ,
SIGPIPE, . , (termination status)
, , . 5.13 [24] SIGPIPE
.
4.8. ,
FIFO ,
(, , 12 [24]), .
, ,
. ( ) FIFO,
( ) . 4.12 , .

29

. 4.12. ,
, /tmp/fif.serv. .
, .
, , .
4.10 .

4.10. ,
FIFO
//fifocliserv/mainserver.
1 #include "fifo.h"
2 void server(int, int);
3 int
4 main(int argc, char **argv)
5 {
6
int readfifo, writefifo, dummyfd, fd;
7
char *ptr, buff[MAXLINE], fifoname[MAXLINE];
8
pid_t pid;
9
ssize_t n;
10 /* FIFO . , */
11 if ((mkfifo(SERV_FIFO, FILE_MODE) < 0) && (errno != EEXIST))
12
err_sys("can't create %s", SERV_FIFO);
13 /* FIFO-cepepa */
14 readfifo = Open(SERV_FIFO, O_RDONLY, 0);
15 dummyfd = Open(SERV_FIFO, O_WRONLY, 0); /* */
16 while ((n = Readline(readfifo, buff, MAXLINE)) > 0) {
17
if (buff[n-1] == '\n')
18
n--; /* delete newline from readline() */
19
buff[n] = '\0'; /* , 0 */
20
if ((ptr = strchr(buff, ' ')) == NULL) {
21
err_msg("bogus request: ls", buff);
22
continue;
23
}
24
*ptr++ = 0; /* , */
25
pid = atol(buff);
26
snprintf(fifoname, sizeof(fifoname), "/tmp/fifo.%ld", (long) pid);
27
if ( (writefifo = open(fifoname, O_WRONLY, 0)) < 0) {
28
err_msg("cannot open: ls", fifoname);
29
continue;
30
}
31
if ((fd = open(ptr, O_RDONLY)) < 0) {
32
/* , */

30

33
snprintf(buff + n, sizeof(buff) n, ": can't open, %s\n",
34
strerror(errno));
35
n = strlen(ptr);
36
Write(writefifo, ptr, n);
37
Close(writefifo);
38
39
} else {
40
/* , */
41
while ((n = Read(fd, buff, MAXLINE)) > 0)
42
Write(writefifo, buff, n);
43
Close(fd);
44
Close(writefifo);
45
}
46 }
47 }



10-15 FIFO , , .
: , . readfifo ,
dummyfd . , , . 4.1. ,
0, .
close, O_RDONLY,
. , , read 0, ,
. read, . open .
open ( O_RDONLY) ,
(. . 4.1). open ( O_WRONLY) , .


16 , , , ,
. readline ( [24, .79]).


17-26 , readline, . ,
, , . strchr
, ,
, . , .
FIFO
27-44 poa-cepepa server 4.3. ;
. , .
() close, read
poae-ey 0 ( ). ;
. poa-ea 4.11.

4.11. ,
( 4.10) FIFO
//fifocliserv/mainclient.
1 #include "fifo.h"
2 int
3 main(int argc, char **argv)
4 {
5
int readfifo, writefifo;
6
size_t len;
7
ssize_t n;
8
char *ptr, fifoname[MAXLINE], buff[MAXLINE];
9
pid_t pid;

31

10 /* FIFO PID */
11 pid = getpid();
12 snprintf(fifoname, sizeof(fifoname), "/tmp/fifo,%ld", (long) pid):
13 if ((mkfifo(fifoname, FILE_MODE) < 0) && (errno != EEXIST))
14
err_sys("can't create %s", fifoname);
15 /* PID */
16 snprintf(buff, sizeof(buff), "%ld ", (long) pid);
17 len = strlen(buff);
18 ptr = buff + len;
19 /* */
20 Fgets(ptr, MAXLINE len, stdin);
21 len = strlen(buff); /* fgets() 0 */
22 /* FIFO PID */
23 writefifo = Open(SERV_FIFO, O_WRONLY, 0);
24 Write(writefifo, buff, len);
25 /* FIFO; */
26 readfifo = Open(fifoname, O_RDONLY; 0);
27 /* IPC, stdout */
28 while ((n = Read(readfifo, buff, MAXLINE)) > 0)
29
Write(STDOUT_FILENO, buff, n);
30 Close(readfifo);
31 Unlink(fifoname);
32 exit(0);
33 }


10-14 .


15-21 , , .
buff, .


22-24 . , open
, open ( O_RDONLY).



25-31 , * .
, , , .
, :

solaris % mainclient /etc/shadow


,
/etc/shadow: can't open. Permission denied
solaris % mainclient /etc/inet/ntp.conf
multicastclient 224.0.1.1
driftfile /etc/inet/ntp.drift
, FIFO .

solaris % Pid=$$
solaris % mkfifo /tmp/fifo.$Pid
solaris % echo "$Pid /etc/inet/ntp.conf" > /tmp/fifo.serv
solaris % cat < /tmp/fifo.$Pid
multicastclient 224.0.1.1
driftfile /etc/inet/ntp.drift

32

solaris % rm /tmp/fifo.$Pid
(echo)
(cat).
. , , cat, .
, - , . . poaoo
FIFO close , , . ,
, , ( ) ( .
4.1). cat , . ,
(denial-of-service attack), .
.
eaopa , FIFO /tmp. ,
:

solaris % cat > /tmp/fifo.serv /no/process/id


999999 /invalid/process/id
:

solaris % server
bogus request: /no/process/id
cannot open: /tmp/fifo.999999
FIFO
- poae FIFO.
, . :

1234 /etc/inet/ntp.conf
:

9876 /etc/passwd
, FIFO write a , PIPE_BUF
( , PIPE_BUF 1024-5120, oaea 1024 ),
, FIFO :

1234 /etc/inet/ntp.conf
9876 /etc/passwd

9876 /etc/passwd
1234 /etc/inet/ntp.conf
, :

1234 /etc/inet9876 /etc/passwd


/ntp.conf
FIFO NFS
FIFO IPC, . FIFO
, , (NFS).

solaris % mkfifo /nsf/bsdi/usr/rstevens/fifo.temp


mkfifo: I/O error
/nfs/bsdi/usr /usr a ye bsdi.
(, BSD/OS) FIFO ,
.
. , , e oem FIFO , ,
, .
4.9.
(iterative server).
, . ,
, 10- , , , 10 , 10 , 10 , .
(concurrent server). Unix one-child-perclient ( ). fork , .
, Unix
. , 27 [24]:
;
poaoo ;
.
[24] , (IPC server),
.

,
, . .
, 4.11, , open FIFO
, ( cat). ,
, . (Denial of Service DoS). ,
,
. ,
, , ,
. : ,
fork.
4.10.
poax FIFO -, Unix.
a . , 100 FIFO,
, FIFO 100 1 , 5 20 , 100 .
, FIFO 55 , 45. ,
. - ,
.

33

, . , ,
: , .
:
1. : Unix
. , .
4.10 4.11, . -
( ).
2. : . .
Sun RPC TCP.
, , , .
3. : ( TCP
IPC), . , HTTP
1.0.
- poa FIFO.
pi, , , ,
fdopen. FIFO , fopen.
Posix, System V.
, ( System V).
. , eaaa UDP ([24]).
, FIFO, .
mesg.h, 4.12.

4.12. mymesg

//pipemesg/mesg.h
1 #include "unpipc.h"
2 /* "", , FIFO
*/
3 /* , sizeof(struct mymesg) <= PIPE_BUF */
4 #define MAXMESGDATA (PIPE_BUF 2*sizeof(long))
5 /* mesg_len mesg_type */
6 #define MESGHDRSIZE (sizeof(struct mymesg) MAXMESGDATA)
7 struct mymesg {
8
long mesg_len; // mesg_data,
9
long mesg_type;// , > 0
10 char mesg_data[MAXMESGDATA];
11 };
12 ssize_t mesg_send(int, struct mymesg *);
13 void Mesg_send(int, struct mymesg *);
14 ssize_t mesg_recv(int, struct mymesg *);
15 ssize_t Mesg_recv(int, struct mymesg *);
(mesg_type), .
, 6, System V.
, oop . mymesg
. :
.
. 4.13 mymesg , FIFO System V.

. 4.13. mymesg

. 4.13 mesg_send, 4.14


mesg_recv.

34

4.13. mesg_send
//pipemesg/mesg_send.c
1 #include "mesg.h"
2 ssize_t
3 mesg_send(int fd, struct mymesg *mptr)
4 {
5 return(write(fd, mptr, MESGHDRSIZE + mptr->mesg_len));
6 }

4.14. mesg_recv
//pipemesg/mesg_recv.c
1 #include "mesg.h"
2 ssize_t
3 mesg_recv(int fd, struct mymesg *mptr)
4 {
5
size_t len;
6
ssize_t n;
8
/* */
9
if ((n = Read(fd, mptr, MESGHDRSIZE)) == 0)
10
return(0); /* end of file */
11 else if (n != MESGHDRSIZE)
12
err_quit("message header: expected %d, got %d". MESGHDRSIZE, n);
13 if ((len = mptr->mesg_len) > 0)
14
if ((n = Read(fd, mptr->mesg_data, len)) != len)
15
err_quit("message data: expected %d, got %d", len, n);
16 return(len);
17 }
read : ,
( 0).

, mesg_recv
. - Mesg_recv .
client server, mesg_send mesg_recv. 4.15 .

4.15. client

//pipemesg/client.c
1 #include "mesg.h"
2 void
3 client(int readfd, int writefd)
4 {
5
size_t len;
6
ssize_t n;
7
struct mymesg mesg;
8
/* */
9
Fgets(mesg.mesg_data, MAXMESGDATA, stdin);
10 len = strlen(mesg.mesg_data);
11 if (mesg.mesg_data[len-1] == '\n')
12
len--; /* fgets() */
13 mesg.mesg_len = len;
14 mesg.mesg_type = 1;
15 /* IPC */
16 Mesg_send(writefd, &mesg);
17 /* IPC. stdout */

35

18 while ( (n = Mesg_recv(readfd, &mesg)) > 0)


19
Write(STDOUT_FILENO, mesg.mesg_data, n);
20 }


8-16 mesg_send.



17-19 mesg_recv , . , mesg_recv
, . ,
, , 1. 4.16 -.

4.16. server,

//pipemesg/server.c
1 #include "mesg.h"
2 void
3 server(int readfd, int writefd)
4 {
5
FILE *fp;
6
ssize_t n;
7
struct mymesg mesg;
8
/* */
9
mesg.mesg_type = 1;
10 if ((n = Mesg_recv(readfd, &mesg)) == 0)
11
err_quit("pathname missing");
12 mesg.mesg_data[n] = '\0'; /* , 0 */
13 if ((fp = fopen(mesg.mesg_data, "r")) == NULL) {
14
/* , */
15
snprintf(mesg.mesg_data + n, sizeof(mesg.mesg_data) n,
16
": can't open, %s\n", strerror(errno));
17
mesg.mesg_len = strlen(mesg.mesg_data);
18
Mesg_send(writefd, &mesg);
19 } else {
20
/* , */
21
while (Fgets(mesg.mesg_data, MAXMESGDATA, fp) != NULL) {
22
mesg.mesg_len = strlen(mesg.mesg_data);
23
Mesg_send(writefd, &mesg);
24
}
25
Fclose(fp);
26 }
27 /* */
28 mesg.mesg_len = 0;
29 Mesg_send(writefd, &mesg);
30 }

IPC,

8-18 . mesg_type, 1, ( mesg_recv


4.14), System V ( 6.8),
(., , 6.11). - fopen , 4.3,

36

open . , fopen, , poae


fgets .


19-26 fopen , fgets .
.
poax FIFO IPC, ,
. , IPC .
main, client server, .
( 4.1), FIFO ( 4.6).
4.11. FIFO
FIFO :
OPEN_MAX , (Posix
16);
PIPE_BUF , ( 4.7; Posix
512 ).
OPEN_MAX , sysconf, .
ulimit ( Bourne shell KornShell, ) limit ( shell).
setrlimit ( 7.11 [21]).
PIPE_BUF , Posix ,
. , ( FIFO,
), .
poa, pathconf, fpathconf. 4.17 ,
oae.

4.17. PIPE_BUF
OPEN_MAX
//pipe/pipeconf.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5
if (argc != 2)
6
err_quit("usage: pipeconf ");
7
printf("PIPE_BUF = %ld. OPEN_MAX = %ld\n",
8
Pathconf(argv[1], _PC_PIPE_BUF), Sysconf(_SC_OPEN_MAX));
9
exit(0);
10 }
, , :

solaris % pipeconf / Solaris 2.6


PIPE_BUF = 5120, OPEN_MAX = 64
solaris % pipeconf /home
PIPE_BUF = 5120, OPEN_MAX = 64
solaris % pipeconf /tmp
PIPE_BUF = 5120, OPEN_MAX = 64
alpha % pipeconf /
Digital Unix 4.0B
PIPE_BUF = 4096, OPEN_MAX = 4096
alpha % pipeconf /usr
PIPE_BUF = 4096, OPEN_MAX = 4096
, OPEN_MAX Solaris, KornShell:

solaris % ulimit nS


64
solaris % ulimit Nh


1024
solaris % ulimit nS 512 512
solaris % pipeconf /

PIPE_BUF = 5120, OPEN_MAX = 512

PIPE_BUF FIFO, , , ,
.

37

2 [21] fpathconf, pathconf sysconf,


. Posix.1 12 , __, 52, _SC_. Digital Unix 4.0B Solaris 2.6
, 100 ,
sysconf.
getconf Posix.2 . :

alpha % getconf OPEN_MAX


4096
alpha % getconf PIPE_BUF /
4096
4.12.
.
() ,
. , (pi, fork, close, exec waitpid), popen pclose,
.
FIFO , mkfifo open. FIFO
, , (. . 4.1).
FIFO, -: ,
. ;
.
.
FIFO , , TCP.
. ,
, , UDP.

1. . 4.3 . 4.4: , (close(fd[1]))?


2. mkfifo 4.6, , FIFO , ,
mkfif, , EEXIST, open, . open,
mkfif, FIFO ?
3. popen 4.5, ?
4. open FIFO 4.10 ,
.
5. 4.10: , open, FIFO
. , open ,
readline?
6. 4.11, open?
7. , FIFO , ,
?
8. , fstat FIFO st_size
stat.
9. , select
, .
5
Posix
5.1.
.
, .
( 4.10), .
. FIFO,
, .
- , ,
. , (kernel persistence, 1.3).
FIFO. 4 , , , ,
.
Posix, 6 System V. ,
:
Posix ,
System V ;
Posix ,
System V .
:
( , Posix) ( long, System V);
, ;
( 0).
FIFO. ,
. 4.10
FIFO. . 5.1 .

. 5.1. Posix,

38

, :
. 5.3.
, , , .
IPC ( 1.3), ,
, . , ,
Posix, , , ,
. , ,
mq_receive.
5.2. mq_open, mq_close, mq_ unlink
mq_open :

#include
mqd_t mq_open(const char *name, int oflag,
/* mode_t mode, struct mq_attr *attr*/ );
/* ;
1 . */
2.2.
oflag : O_RDONLY, O_WRONLY, O_RDWR ( ) O_CREAT,
O_EXCL, O_NONBLOCK. 2.3.
( O_CREAT ) mode attr.
mode . 2.3. attr .
, . 5.3.
mq_open , (, ,
) , .
.

Solaris 2.6 mqd_t void*, Digital Unix 4.0B int. 5.8


. .
mq_close:

#include
int mq_close(mqd_t mqdes);
/* 0 . 1 */
close : ,
. ,
mq_close.
(), mq_open, mq_unlink:

#include
int mq_unlink(const char *name);
/* 0 . 1 */
( ) , ,
unlink : () , , (
) , .
Posix ( 1.3), ,
, , . , mq_unlink.

, ( 12.2),
, .
: mqcreate1
Posix ,
. 5.1 [1] ,
.

5.1. (
O_EXCL)
//pxmsg/mqcreate1.
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5
int flags:
6
mqd_t mqd;
7
flags = O_RDWR | O_CREAT;
8
while ((c = Getopt(argc, argv, "e")) != 1) {
9
switch (c) {
10
case 'e':
11
flags |= O_EXCL;
12
break;

39

13
}
14 }
15 if (optind != argc 1)
16
err_quit("usage: mqcreate [ e ] ");
17 mqd = Mq_open(argv[optind], flags, FILE_MODE, NULL);
18 Mq_close(mqd);
19 exit(0);
20 }
, . ( getopt Getopt
5.5.) getopt optind ,
.
mq_open, IPC ,
2.2 px_ipc_name. , Posix IPC (
).
Solaris 2.6:

solaris % mqcreate1 /temp.1234



solaris % ls -l /tmp/.*1234
-rw-rw-rw 1 rstevens other1 132632 Oct 23 17:08 /tmp/.MQDtemp.1234
-rw-rw-rw 1 rstevens other1
0 Oct 23 17:08 /tmp/.MQLtemp.1234
-rw-r--r-- 1 rstevens other1
0 Oct 23 17:08 /tmp/.MQPDtemp.1234
solaris % mqcreate1 e /temp.1234
mq_open error for /temp.1234: File exists
mqcreate1, 5.4,
. FILE_MODE ( ,
), . , D ;
L - , .
Digital Unix 4.0B :

alpha % mqcreate1 /tmp/myq.1234



alpha % ls l /tmp/myq.1234
-rw-r--r-- 1 rstevens system 11976 Oct 23 17:04 /tmp/myq.1234
alpha % mqcreate1 e /tmp/myq.1234
mq_open error for /tmp/myq.1234: File exists
: mqunlink
5.2 mqunlink, .

5.2. : mqunlink
//pxmsg/mqunlink.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5 if (argc != 2)
6
err_quit("usage: mqunlink ");
7 Mq_unlink(argv[1]);
8 exit(0);
9 }
, mqcreate1:

solaris % mqunlink /temp.1234


/tmp, .
5.3. mq_getattr mq_ setattr
, mq_getattr ( )
mq_setattr:

#include
int mq_getattr(mqd_t mqdes, struct mq_attr *attr);
int mq_setattr(mqd_t mqdes, const struct mq_attr *attr, struct mq_attr *oattr);
/* 0 ; 1
*/
mq_attr :

struct mq_attr {
long mq_flags;
/* : 0, O_NONBLOCK */
long mq_maxmsg; /* */
long mq_msgsize; /* ( ) */

40

long mq_curmsgs; //
}
mq_open,
mq_maxmsg mq_msgsize . mq_open .
mq_getattr , attr, .
mq_setattr , mqflags , attr,
. :
,
, .
, oattr , (mq_flags, mq_maxmsg, mq_msgsize)
(mq_curmsgs).
: mqgetattr
5.3 .

5.3.

//pxmsg/mqgetattr.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5
mqd_t mqd;
6
struct mq_attr attr;
7
if (argc != 2)
8
err_quit("usage: mqgetattr ");
9
mqd = Mq_open(argv[1], O_RDONLY);
10 Mq_getattr(mqd, &attr);
11 printf ("max #msgs = %ld, max #bytes/msg = %ld, "
12
"#currently on queue = %ld\n",
13
attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
14 Mq_close(mqd);
15 exit(0);
16 }
, :

solaris % mqcreate1 /hello.world


solaris % mqgetattr /hello.world
max #msgs = 128, max #bytes/msg = 1024, #currently on queue = 0
, .
ls 5.1. 1281024+1560 = 132632.
1560 , , : 8 536 .
: mqcreate
5.1 ,
. ; (., ,
5.1). 5.4 .

5.4.
mqcreate
//pxmsg/mqcreate.c
1 #include "unpipc.h"
2 struct mq_attr attr; /* mq_maxmsg mq_msgsize */
3 int
4 main(int argc, char **argv)
5 {
6
int flags;
7
mqd_t mqd;
8
flags = O_RDWR | O_CREAT;
9
while ((c = Getopt(argc, argv, "em:z:")) != 1) {
10
switch (c) {
11
case 'e':

41

12
flags |= O_EXCL;
13
break;
14
case 'm':
15
attr.mq_maxmsg = atol(optarg);
16
break;
17
case 'z':
18
attr.mq_msgsize = atol(optarg);
19
break;
20
}
21 }
22 if (optind != argc 1)
23
err_quit("usage: mqcreate [ ] [ m maxmsg z msgsize ] ");
24 if ((attr.mq_maxmsg != 0 && attr.mq_msgsize ==0) ||
25
(attr.mq_maxmsg == 0 && attr.mq_msgsize != 0))
26
err_quit("must specify both m maxmsg and z msgsize");
27 mqd = Mq_open(argv[optind], flags, FILE_MODE,
28
(attr.mq_maxmsg != 0) ? &attr : NULL);
29 Mq_close(mqd);
30 exit(0);
31 }
, , ( m z getopt).
optarg .

Getopt getopt
: , ,
( getopt). , getopt
, Getopt.
getopt:

solaris %mqcreate z
mqcreate: option requires an argument z
solaris %mqcreate q
mqcreate: illegal option q

( ) :

solaris %mqcreate
usage: mqcreate [ e ] [ m maxmsg z msgsize ]

, mq_open .
attr.
Solaris 2.6, 1024
8192 :

solaris % mqcreate e m 1024 -z 8192 /foobar


solaris % ls al /tmp/.*foobar
-rw-rw-rw 1 rstevens other1 8397336 Oct 25 11:29 /tmp/.MQDfoobar
rw-rw-rw 1 rstevens other1
0 Oct 25 11:29 /tmp/.MQLfoobar
rw-r--r-- 1 rstevens other1
0 Oct 25 11:29 /tmp/.MQPfoobar
, ,
(10248192 = 8388608), 8728 8 (81024) 536
.
Digital Unix 4.0B :

alpha % mqcreate m 256 -z 2048 /tmp/bigq


alpha % ls-l/tmp/bigq
-rw-r--r-- 1 rstevens system 537288 Oct 25 15:38 /tmp/bigq
(2562048 = 524288),
13000 48 (48256) 712 .
5.4. mqsend mqreceive
. ,
, MQ_PRIO_MAX. Posix , 32.

Solaris 2.6 MQ_PRIO_MAX 32, Digital Unix 4.0B 256. 5.7 ,


.
mq_receive ,
.

mq_receive msgrcv System V ( 6.4). System V type, ,


msgrcv : ,
, .

#include
int mq_send(mqd_t mqdes, const char *ptr, size_t len, unsigned int prio);
/* 0 , 1
*/

42

ssize_t mq_receive(mqd_t mqdes, char *ptr, size_t len, unsigned int *priop);
/* . 1
*/
write read .

char* void* Posix.1.


len mq_receive ,
, mq_msgsize mq_attr . len ,
EMSGSIZE.

, , Posix, mq_getattr
, . ,
, , mq_receive ,
. , , MSG_NOERROR E2BIG System V ( 6.4)
MSG_TRUNC recvmsg, UDP ( 13.5 [24]).
prio mq_send, MQ_PRIO_MAX. mq_receive priop
, .
, mq_send mq_receive .

. , , (Posix.1), ,
: . mq_receive (
) 1 , 0 .
Posix System V : .
. , IPC
. 15.5 , . 14.8 [24] ,
BSD/OS Unix. 15.3.1 [21] , SVR4
. BSD/OS , SVR4 Unix 98,
, , .
(, ) ,
, . ,
, . (
System V 6.8), . ,
( 5.8), ,
, , .
: mqsend
5.5 , .

5.5. mqsend
//pxmsg/mqsend.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5
mqd_t mqd;
6
void *ptr;
7
size_t len;
8
uint_t prio;
9
if (argc != 4)
10
err_quit("usage: mqsend <#bytes> ");
11 len = atoi(argv[2]);
12 prio = atoi(argv[3]);
13 mqd = Mq_open(argv[1], O_WRONLY);
14 ptr = Calloc(len, sizeof (char));
15 Mq_send(mqd, ptr, len, prio);
16 exit(0);
17 }
, . call,
.
: mqreceive
5.6 .

5.6. mqreceive
//pxmsg/mqreceive.
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)

43

4 {
5
int flags;
6
mqd_t mqd;
7
ssize_t n;
8
uint_t prio;
9
void *buff;
10 struct mq_attr attr;
11 flags = O_RDONLY;
12 while ((c = Getopt(argc, argv, "n")) != 1) {
13
switch (c) {
14
case 'n':
15
flags |= O_NONBLOCK;
16
break;
17
}
18 }
19 if (optind != argc 1)
20
err_quit("usage: mqreceive [ n ] ");
21 mqd = Mq_open(argv[optind], flags);
22 Mq_getattr(mqd, &attr);
23 buff = Malloc(attr.mqjnsgsize);
24 n = Mq_receive(raqd, buff, attr.mq_msgsize, &prio);
25 printf("read %ld bytes, priority = %u\n", (long) n, prio);
26 exit(0);
27 }

-n
14-17 n . , .


21-25 , mq_getattr. ,
, mq_receive.
.

n size_t , int long, long %ld. 64 int 32- , a long size_t 64- .
, .

solaris % mqcreate /test1


solaris % mqgetattr /test1

max #msgs = 128, max #bytes/msg = 1024, #currently on queue = 0
solaris % mqsend /test1 100 99999
mq_send error: Invalid argument
solaris % mqsend /test1 100 6
100 , 6
solaris % mqsend /test1 50 18
50 , 18
solaris % mqsend /test1 33 18
33 , 18
solaris % mqreceive /test1
read 50 bytes, priority = 18

solaris % mqreceive /test1

read 33 bytes, priority = 18
Solaris % mqreceive /test1
read 100 bytes, priority = 6
Solaris % mqreceive n /test1
,

mq_receive error: Resource temporarily unavailable


, mq_receive .
5.5.
, :
mq_maxmsg ;
mq_msgsize .

44

- ,
. , (. 5.5).
:
MQ_OPEN_MAX , - (Posix ,
8);
MQ_PRIO_MAX (Posix , 32).
sysconf,
.
: mqsysconf
5.7 sysconf , .

5.7.
sysconf
//pxmsg/mqsysconf.
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5 printf("MQ_OPEN_MAX = %ld, MQ_PRIO_MAX = %ld\n",
6 Sysconf(_SC_MQ_OPEN_MAX), Sysconf(_SC_MQ_PRIO_MAX));
7 exit(0);
8 }
, :

solaris % mqsysconf
MQ_OPEN_MAX = 32, MQ_PRIO_MAX = 32
alpha % mqsysconf
MQ_OPEN_MAX = 64, MQ_PRIO_MAX = 256
5.6. mq_n otify
System V, 6, ,
. msgrcv,
. msgrcv (IPC_NOWAIT), ,
, , . ,
. , , .

, .
Posix , .
, .
mq_notify:

#include
int mq_notify(mqd_t mqdes, const struct sigevent *notification);
/* 0 , 1 */
. sigevent
Posix.1 , . ,
, :

union sigval {
int sival_int; /* */
void *sival_ptr; /* */
};
struct sigevent {
int sigev_notify; /* SIGEV_{NONE,SIGNAL,THREAD} */
int sigev_signo; /* , SIGEV_SIGNAL */
union sigval sigev_value; /* */
/* SIGEV_THREAD */
void (*sigev_notify_function) (union sigval);
pthread_attr_t *sigev_notify_attributes;
, , ,
.
1. notification , ,
. , .
2. notification ,
.
3. .
4. , ,
, mq_receive . , mq_receive
.

45

5. . (
), mq_notify .

Unix :
( 10.4 [21]). , , signal, .
,
. , mq_notify,
. ,
, . ,
.
:
Posix, ,
SI6USR1 . 5.8, , ,
.

5.8. sigusr1
(
)
//pxmsg/mqnotifysigl.c
1 #include "unpipc.h"
2 mqd_t mqd;
3 void *buff;
4 struct mq_attr attr;
5 struct sigevent sigev;
6 static void sig_usrl(int);
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

int
main(int argc, char **argv)
{
if (argc != 2)
err_quit("usage: mqnotifysig1 ");
/* , , */
mqd = Mq_open(argv[1], O_RDONLY);
Mq_getattr(mqd, &attr);
buff = Malloc(attr.mq_msgsize);
/* , */
Signal(SIGUSR1, sig_usr1);
sigev.sigev_notify = SIGEV_SIGNAL;
sigev.sigev_signo = SIGUSR1;
Mq_notify(mqd, &sigev);
for (;;)
pause(); /* */
exit(0);
}

25
26
27
28
29
30
31
32
33

static void
sig_usr1(int signo)
{
ssize_t n;
Mq_notify(mqd, &sigev); /* */
n = Mq_receive(mqd, buff, attr.mq_msgsize, NULL);
printf("SIGUSR1 received, read %ld bytes\n", (long) n);
return;
}


2-6 , main (sig_usr1).

46

, ,

12-15 , .

16-20 SIGUSR1. sigev_notify sigevent


SIGEV_SIGNAL, , . sigev_signo
, , . mq_notify.


main , pause, 1 .

,
mq_notify , .
.

return sig_usr1 , ,
. return , ,
. , ( EINTR) , .

solaris % mqcreate /test1


solaris % mqnotifysig1 /test1

solaris % mqsend /test1 50 16


, mqnotifysig1 : SIGUSR1 received, read 50 bytes.
, , poa
:

solaris % mqnotifysig1 /test1


mq_notify error: Device busy
EBUSY.
Posix: Async-Signal-Safe
poa 5.8 , mq_notify, mq_receive printf .
.
, , , , Posix, async-signal-safe functions (,
). . 5.1 Posix
, Unix 98.
, , . ,
- pthread_XXX . IPC, ,
sem_post, read write (, FIFO).

ANSI , : abort, exit, longjmp, signal.


async-signal-safe Unix 98.
5.1. , async-signal-safe

access
aio_return
aio_suspend
alarm
cfgetispeed
cfgetospeed
cfsetispeed
cfsetospeed
chdir
chmod
chown
clock_gettime
close

fpathconf
fstat
fsync
getegid
geteuid
getgid
getgroups
getpgrp
getpid
getppid
getuid
kill
link

rename
rmdir
sem_post
setgid
setpgid
setsid
setuid
sigaction
sigaddset
sigdelset
sigemptyset
sigfillset
sigismember

sysconf
tcdrain
tcflow
tcflush
tcgetattr
tcgetgrp
tcsendbreak
tcsetattr
tcsetpgrp
time
timer_getoverrun
timer_gettime
timer_settime

47

creat
dup
dup2
execle
execve
_exit
fcntl
fdatasync
fork

lseek
mkdir
mkfifo
open
pathconf
pause
pipe
raise
read

signal
sigpause
sigpending
sigprocmask
sigqueue
sigset
sigsuspend
sleep
stat

times
umask
uname
unlink
utime
wait
waitpid
write

:
- ,
. 5.9 ,
, , .


2 , , mqflag,
5.8 . ,
.


15-18 , .


19-22 SIGUSR1 newmask.

23-27 SIGUSR1, sigevent mq_notify.

5.9.
( )
//pxmsg/mqnotifysig2.c
1 #include "unpipc.h"
2 volatile
sig_atomic_t
mqflag;
*/
3 static void sig_usrl(int);

/*

4 int
5 main(int argc, char **argv)
6 {
7
mqd_t mqd;
8
void *buff;
9
ssize_t n;
10 sigset_t zeromask, newmask, oldmask;
11 struct mq_attr attr;
12 struct sigevent sigev;
13 if (argc != 2)
14
err_quit("usage: mqnotifysig2 ");
15 /* , , */
16 mqd = Mq_open(argv[1], O_RDONLY);
17 Mq_getattr(mqd, &attr);

48

18 buff = Malloc(attr.mq_msgsize);
19 Sigemptyset(&zeromask); /* */
20 Sigemptyset(&newmask);
21 Sigemptyset(&oldmask);
22 Sigaddset(&newmask, SIGUSR1);
23 /* , */
24 Signal(SIGUSR1, sig_usr1);
25 sigev.sigev_notify = SIGEV_SIGNAL;
26 sigev.sigev_signo = SIGUSR1;
27 Mq_notify(mqd, &sigev);
28 for (;;) {
29
Sigprocmask(SIG_BLOCK, &newmask, &oldmask); /* SIGUSR1 */
30
while (mqflag == 0)
31
sigsuspend(&zeromask);
32
mqflag = 0; /* */
33
Mq_notify(mqd, &sigev); /* */
34
n = Mq_receive(mqd, buff, attr.mq_msgsize, NULL);
35
printf("read %ld bytes\n", (long) n);
36
Sigprocmask(SIG_UNBLOCK, &newmask, NULL); /* SIGUSR1 */
37 }
38 exit(0);
39 }
40
41
42
43
44
45

static void
sig_usr1(int signo)
{
mqflag = 1;
return;
}


28-32 sigprocmask, SIGUSR1, oldmask.
mqflag, , . ,
sigsuspend, zeromask ( ). 10.16 [21]
sigsuspend . , mqflag
SIGUSR1. sigsuspend SIGUSR1 .


33-36 mqflag , .
SIGUSR1 .
, . , , ,
. , sleep mq_notify. ,
, . ,
, . sigsuspend, .
, , .
:
, . 5.10
5.9. .

5.10.

Posix
//pxmsg/mqnotifysig3.
1 #include "unpipc.h"
2 volatile
sig_atomic_t
*/

mqflag;

/*

49

static void sig_usr1(int);

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

int
main(int argc, char **argv)
{
mqd_t mqd;
void *buff;
ssize_t n;
sigset_t zeromask, newmask, oldmask;
struct mq_attr attr;
struct sigevent sigev;
if (argc != 2)
err_quit("usage: mqnotifysig3 ");
/* , , */
mqd = Mq_open(argv[1], O_RDONLY | O_NONBLOCK);
Mq_getattr(mqd, &attr);
buff = Malloc(attr.mq_msgsize);
Sigemptyset(&zeromask); /* */
Sigemptyset(&newmask);
Sigemptyset(&oldmask);
Sigaddset(&newmask, SIGUSR1);
/* , */
Signal(SIGUSR1, sig_usr1);
sigev.sigev_notify = SIGEV_SIGNAL;
sigev.sigev_signo = SIGUSR1;
Mq_notify(mqd, &sigev);
for (;;) {
Sigprocmask(SIG_BLOCK, &newmask, &oldmask); /* SIGUSR1 */
while (mqflag == 0)
sigsuspend(&zeromask);
mqflag = 0; /* */
Mq_notify(mqd, &sigev); /* */
while ((n = mq_receive(mqd, buff, attr.mq_msgsize, NULL)) >= 0) {
printf("read $ld bytes\n", (long) n);
}
if (errno != EAGAIN)
err_sys("mq_receive error");
Sigprocmask(SIG_UNBLOCK, &newmask, NULL); /* SIGUSR1 */
}
exit(0);
}

43
44
45
46
47
48

static void
sig_usr1(int signo)
{
mqflag = 1;
return;
}

15-18 : O_NONBLOCK.


50

34-38 : mq_receive , , EAGAIN,


.
: sigwait
, . sigsuspend
. , , ,
mqflag, , , mqflag , .
, ,
. sigwait:

#include
int sigwait(const sigset_t *set, int *sig);
/* 0 , 1 */
sigwait . set. sigwait
, . , .
sig, 0. : ,
.
5.11 , mq_notif sigwait.

5.11. mq_notify
sigwait
//pxmsg/mqnotifysig4.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

int
main(int argc, char **argv)
{
int signo;
mqd_t mqd;
void *buff;
ssize_t n;
sigset_t newmask;
struct mq_attr attr;
struct sigevent sigev;
if (argc != 2)
err_quit("usage: mqnotifysig4 ");
/* , , */
mqd = Mq_open(argv[1], O_RDONLY | O_NONBLOCK);
Mq_getattr(mqd, &attr);
buff = Malloc(attr.mq_msgsize);
Sigemptyset(&newmask);
Sigaddset(&newmask, SIGUSR1);
Sigprocmask(SIG_BLOCK, &newmask, NULL); /* SIGUSR1 */
/* , */
sigev.sigev_notify = SIGEV_SIGNAL;
sigev.sigev_signo = SIGUSR1;
Mq_notify(mqd, &sigev);
for (;;) {
Sigwait(&newmask, &signo);
if (signo == SIGUSR1) {
Mq_notify(mqd, &sigev); /* */
while ((n = mq_receive(mqd, buff, attr.mq_msgsize, NULL)) >= 0) {
printf("read %ld bytes\n", (long) n);
}
if (errno != EAGAIN)
err_sys("mq_receive error");
}
}
exit(0);
}

51


SIGUSR1
18-20 , SIGUSR1, sigprocmask.


26-34 , sigwait. SIGUSR1
.

sigwait . , , ,
0 , Pthread. sigprocmask
pthread_ sigmask, . pthread_sigmask
sigprocmask.
sigwait: sigwaitinfo siginfo_t ( )
; sigtimedwait siginfo_t
.
, [3], sigwait
.
: Posix select
( mqd_t) select poll
( 6 [24]). mq_notify. ( 6.9
System V, .) , , . 5.1, write
async-signal-safe, . 5.12.

5.12.

//pxmsg/mqnotifysig5.c
1 #include "unpipc.h"
2 int pipefd[2];
3 static void sig_usr1(int);
4 int
5 main(int argc, char **argv)
6 {
7
int nfds;
8
char c;
9
fd_set rset;
10 mqd_t mqd;
11 void *buff;
12 ssize_t n;
13 struct mq_attr attr;
14 struct sigevent sigev;
15 if (argc != 2)
16
err_quit("usage: mqnotifysig5 ");
17 /* , , */
18 mqd = Mq_open(argv[1], O_RDONLY | O_NONBLOCK);
19 Mq_getattr(mqd, &attr);
20 buff = Malloc(attr.mq_msgsize);
21 Pipe(pipefd);
22 /* , */
23 Signal(SIGUSR1, sig_usr1);
24 sigev.sigev_notify = SIGEV_SIGNAL;
25 sigev.sigev_signo = SIGUSR1;
26 Mq_notify(mqd, &sigev);
27 FD_ZERO(&rset);
28 for (;;) {
29
FD_SET(pipefd[0], &rset);
30
nfds = Select(pipefd[0] + 1, &rset, NULL, NULL, NULL);

52

31
if (FD_ISSET(pipefd[0], &rset)) {
32
Read(pipefd[0], &c, 1);
33
Mq_notify(mqd, &sigev); /* */
34
while ((n = mq_receive(mqd, buff, attr.mq_msgsize, NULL)) >= 0) {
35
printf("read %ld bytes\n", (long) n);
36
}
37
if (errno != EAGAIN)
38
err_sys("mq_receive error");
39
}
40 }
41 exit(0);
42 }
43
44
45
46
47
48

static void
sig_usr1(int signo)
{
Write(pipefd[1], "", 1); /* 0 */
return;
}


21 , , .
.

select
27-40 rset , pipefd[0] (
). select, ,
. ,
.


43-48 , , 1 . ,
.
:
sigev_notify SIGEV_THREAD, .
, sigev_notify_function, sigev_value. sigev_notify_attributes,
, . 5.13.

5.13. mq_notify,

//pxmsg/mqnotifythread1.
1 #include "unpipc.h"
2 mqd_t mqd;
3 struct mq_attr attr;
4 struct sigevent sigev;
5 static void notify_thread(union sigval); /* */
6 int
7 main(int argc, char **argv)
8 {
9
if (argc != 2)
10
err_quit("usage: mqnotifythread1 ");
11 mqd = Mq_open(argv[1], O_RDONLY | O_NONBLOCK);
12 Mq_getattr(mqd, &attr);

53

13 sigev.sigev_notify = SIGEV_THREAD;
14 sigev.sigev_value.sival_ptr = NULL;
15 sigev.sigev_notify_function = notify_thread;
16 sigev.sigev_notify_attributes = NULL;
17 Mq_notify(mqd, &sigev);
18 for (;;)
19
pause(); /* */
20 exit(0);
21 }
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

static void
notify_thread(union sigval arg)
{
ssize_t n;
void *buff;
printf("notify_thread started\n");
buff = Malloc(attr.mq_msgsize);
Mq_notify(mqd, &sigev); /* */
while ((n = mq_receive(mqd, buff, attr.mq_msgsize, NULL)) >= 0) {
printf("read %ld bytes\n", (long) n);
}
if (errno != EAGAIN)
err_sys("mq_receive error");
free(buff);
pthread_exit(NULL);
}

(sigev_value), start .
, ,
sigev ( ). ,
. (detached threads).

, (Solaris 2.6 Digital Unix 4.0B) SIGEV_THREAD.


sigev_notify: SIGEV_NONE SIGEV_SIGNAL.
5.7. Posix
Unix .
1. , Unix Version 7 (1978), . ,
.
2. 4.3BSD (1986) .
3. System V Release 3.0 (1986) , , BSD.
4. Posix.1 (1990) BSD, 10 [21].
5. Posix.1 (1996) Posix . Posix.1b (
Posix.4).
Unix ,
Posix. ( .)
, , , ( sigval
sigevent).
:
1. , SIGRTMIN SIGRTMAX . Posix ,
RTSIG_MAX , 8.
2. : SIGALRM, SIGINT, SIGKILL .

Solaris 2.6 Unix 1 37, 8 38 45. Digital Unix 4.0B


1 32, 16 33 48. SIGRTMIN SIGRTMAX ,
sysconf, .
, , , SA_SIGINFO sigaction.
, . 5.2.

5.2. Posix SA_SIGINFO

SA_SIGINFO
SIGRTMIN

SIGRTMAX


SA_SIGINFO



:
, . , ,
SIGRTMIN SIGRTMAX SA_SIGINFO sigaction .
:

54

. , . ,
(FIFO). . ,
.
SIGRTMINSIGRTMAX,
. SIGRTMIN , SIGRTMIN+1, ..
, , .
, . , SA_SIGINFO,

void func(int signo, siginfo_t *info, void *context);


signo , a siginfo_t ,

typedef struct {
int si_signo; /* , signo */
int si_code; /* SI_{USER,QUEUE,TIMER,ASYNCIO,MESGQ} */
union sigval si_value; /* */
} siginfo_t;
context .

, , .
, Posix.
siginfo_t Posix, typedef , _t. 5.14
siginfo_t * struct.
. , -
sigqueue kill. sigval.
Posix.1, si_code,
siginfo_t, .
SI_ASYNCIO Posix aio_XXX,
;
SI_MESGQ ( 5.6);
SI_QUEUE sigqueue. ;
SI_TIMER timer_settime . ;
SI_USER kill.
- , si_code , . si_value
siginfo_t , si_code : SI_ASYNCIO, SI_MESGQ, SI_QUEUE SI_TIMER.

5.14 , . fork,
, (
), , .

5.14. ,

//rtsignals/test1.c
1 #include "unpipc.h"
2 static void sig_rt(int, siginfo_t *, void *);
3 int
4 main(int argc, char **argv)
5 {
6
int i, j;
7
pid_t pid;
8
sigset_t newset;
9
union sigval val;
10 printf("SIGRTMIN = %d, SIGRTMAX = %d\n", (int) SIGRTMIN, (int) SIGRTMAX);
11 if ((pid = Fork()) == 0) {
12
/* 3 */
13
Sigemptyset(&newset);
14
Sigaddset(&newset, SIGRTMAX);
15
Sigaddset(&newset, SIGRTMAX 1);
16
Sigaddset(&newset, SIGRTMAX 2);
17
Sigprocmask(SIG_BLOCK, &newset, NULL);
18
/* SA_SIGINFO */
19
Signal_rt(SIGRTMAX, sig_rt);
20
Signal_rt(SIGRTMAX 1, sig_rt);
21
Signal_rt(SIGRTMAX 2, sig_rt);
22
sleep(6); /* */
23
Sigprocmask(SIG UNBLOCK, &newset, NULL); /* */

55

24
sleep(3); /* */
25
exit(O);
26 }
27 /* */
28 sleep(3); /* */
29 for (i = SIGRTMAX; i >= SIGRTMAX 2; i--) {
30
for (j = 0; j <= 2; j++) {
31
val.sival_int = j;
32
Sigqueue(pid, i, val);
33
printf("sent signal %d, val = %d\n", i, j);
34
}
35 }
36 exit(0);
37 }
38
39
40
41
42
43

static void
sig_rt(int signo, siginfo_t *info, void *context)
{
printf(received signal #%d, code = %d, ival = %d\n",
signo.info->si_code, info->si_value.sival_int);
}


10 , , .
integer, , sysconf, :

#define SIGRTMAX (sysconf(_SC_RTSIG_MAX))


sysconf long (. 5.4).

fork

11-17 , sigprocmask : SIGRTMAX,


SIGRTMAX-1 SIGRTMAX-2.


18-21 signal_rt ( 5.15) sig_rt
. SA_SIGINFO, ,
, . ,
.


,
22-25 6 , . sigprocmask
. . ,
printf , .


27-36 , .
: i 3 , a j 0, 1 2 i.
, , .
sigval_int, , ,
, .


56

38-43 .

. 5.1 , printf async-signal-safe .


.
Solaris 2.6. , :

solaris % test1
SIGRTMIN = 38, SIGRTMAX = 45 8

sent signal 45, val = 0
sent signal 45, val = 1
sent signal 45, val = 2
sent signal 44, val = 0
sent signal 44, val = 1
sent signal 44, val = 2
sent signal 43, val = 0
sent signal 43, val = 1
sent signal 43, val = 2
solaris % , 3 ,

received signal #45, code = 2, ival = 2
received signal #45, code = 2, ival = 1
received signal #45, code = 2, ival = 0
received signal #44, code = 2, ival = 2
received signal #44, code = 2, ival = 1
received signal #44, code = 2, ival = 0
received signal #43, code = 2, ival = 2
received signal #43, code = 2, ival = 1
received signal #43, code = 2, ival = 0
, (
).
, LIFO, FIFO. si_code = 2 SI_QUEUE.
Digital Unix 4.0B, , :

alpha % test1
SIGRTMIN = 33, SIGRTMAX = 48 16

sent signal 48, val = 0
sent signal 48, val = 1
sent signal 48, val = 2
sent signal 47, val = 0
sent signal 47, val = 1
sent signal 47, val = 2
sent signal 46, val = 0
sent signal 46, val = 1
sent signal 46, val = 2
alpha % , 3 .

received signal #46, code 1, ival = 0
received signal #46, code = 1, ival = 1
received signal #46, code = 1, ival = 2
received signal #47, code 1, ival = 0
received signal #47, code = 1, ival = 1
received signal #47, code = 1, ival = 2
received signal #48, code = 1, ival = 0
received signal #48, code = 1, ival = 1
received signal #48, code = 1, ival = 2
: ,
FIFO.

, Solaris 2.6 .
sign al_rt
[24, . 120] signal, sigaction Posix
, Posix. , .
signal_rt; 5.15.

57

5.15. signal_rt

//lib/signal_rt.c
1 #include "unpipc.h"
2 Sigfunc_rt *
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

signal_rt(int signo, Sigfunc_rt *func)


{
struct sigaction act, oact;
act.sa_sigaction = func; /* */
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO; /* */
if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
#endif
} else {
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */
#endif
}
if (sigaction(signo, &act, &oact) < 0)
return((Sigfunc_rt *) SIG_ERR);
return(oact.sa_sigaction);
}


typedef
1-3 unpi.h ( .1) Sigfunc_rt

typedef void Sigfunc_rt(int, siginfo_t*, void*);


, , SA_SIGINFO.

-
sigaction -5-7 : sa_sigaction:

struct sigaction {
void (*sa_handler)(); /* SIG_DFL, SIG_IGN */
sigset_t sa_mask; /* */
int sa_flags; /* : SA_XXX */
void (*sa_sigaction)(int, siginfo_t, void *);
};
:
sa_flags SA_SIGINFO, sa_sigaction - .
SA_SIGINFO , sa_handler - .
, sa_handler SIG_DFL, SIG_IGN
SA_SIGINFO.

SA_SIGINFO
Posix.

8-17 SA_SIGINFO SA_RESTART, - , SIGALRM.


5.8.
Posix ,

7, - 12 13.
.

58

. 5.2 , Posix.
7 .
5.16 mqueue.h, , .

mqd_t
mq_inf. mq_open
, . , ,
, Posix, , .

5.16. mqueue.h
//my_pxmsg_mmap/mqueue.h
1 typedef struct mymq_info *mymqd_t;
2
3
4
5
6
7

struct mymq_attr {
long mq_flags; /* : O_NONBLOCK */
long mq_maxmsg; /* */
long mq_msgsize; /* */
long mq_curmsgs; /* */
};

8 /* mymq_hdr{} , */
9 struct mymq_hdr {
10 struct mymq_attr mqh_attr; /* */
11 long mqh_head; /* */
12 long mqh_free; /* */
13 long mqh_nwait; /* mq_receive() */
14 pid_t mqh_pid; /* PID. */
15 struct sigevent mqh_event; /* mq_notify() */
16 pthread_mutex_t mqh_lock; /* : mutex*/
17 pthread_cond_t mqh_wait; /* */
18 };
19 /* mymsg_hdr{} */
20 struct mymsg_hdr {
21 long msg_next; /* */
22
/* msg_next */
23 ssize_t msg_len; /* */
24 unsigned int msg_prio; /* */
25 };
26
27
28
29
30
31
32
33
34

/* mymq_info{} mq_open() */
struct mymq_info {
struct mymq_hdr *mqi_hdr; /* */
long mqi_magic; /* */
int mqi_flags; /* */
};
#define MQI_MAGIC 0x98765432
/* */
#define MSGSIZE(i) ((((i) + sizeof(long)-1) / sizeof(long)) * sizeof(long))

59

. 5.2. , posix

mq_hdr
8-18 . mq_flags mqh_attr
, ( )
, . mq_info.
.
, , ( mqh_head mqh_free, msg_next
), . , mq_hdr Solaris
2.6 96 , , , 96. . 5.2 20
(12 msg_hdr 8 ), 116, 136 156,
176 . , :
(mqh_head) , , (mqh_free) .
() ,
, ( 13.5).

msg_hdr
19-25 .
, , msg_next ( 0,

60

). msg_len , . 5.2 0
7 . msg_prio .

mq_info
26-32 mq_open mq_close. mqi_hdr
( mmap). mqd_t,
, mq_open.
mqi_magi MQI_MAGIC . ,
mqd_t, , mq_inf. mqi_flags
.

MSGSIZE
33-34 (alignment) ,
. , , 1 3 ,
. 5.2. , 4 ( Solaris 2.6). 8 (
Digital Unix 4.0B), 1 7 .
mq_open
5.17 mq_open, .

5.17. mq_open:
//my_pxmsg._mmap/mq_open.
1 #include "unpipc.h"
2 #include "mqueue.h"
3 #include
4 #define MAX_TRIES 10
5 struct mymq_attr defattr =
6
{ 0, 128, 1024, 0 };
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

mymqd_t
mymq_open(const char *pathname, int oflag, )
{
int i, fd, nonblock, created, save_errno;
long msgsize, filesize, index;
va_list ap;
mode_t mode;
int8_t *mptr;
struct stat statbuff;
struct mymq_hdr *mqhdr;
struct mymsg_hdr *msghdr;
struct mymq_attr *attr;
struct mymq_info *mqinfo;
pthread_mutexattr_t mattr;
pthread_condattr_t cattr;
created = 0;
nonblock = oflag & O_NONBLOCK;
oflag &= ~O_NONBLOCK;
mptr = (int8_t *) MAP_FAILED;
mqinfo = NULL;
again:
if (oflag & O_CREAT) {
va_start(ap, oflag); /* */
mode = va_arg(ap, va_mode_t) & ~S_IXUSR;
attr = va_arg(ap, struct mymq_attr *);
va_end(ap);
/* user-execute */
fd = open (pathname, oflag | O_EXCL | O_RDWR, mode | S_IXUSR);
if (fd < 0) {

61

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

if (errno == EEXIST && (oflag & O_EXCL) == 0)


goto exists; /* , OK */
else
return((mymqd_t) 1);
}
created = 1;
/* */
if (attr == NULL)
attr = &defattr;
else {
if (attr->mq_maxmsg < 0 || attr->mq_msgsize <= 0) {
errno = EINVAL;
goto err;
}
}


29-32 , , O_CREAT. ,
mode_t, , . BSD/OS,
unsigned short (16 ). 32 ,
16 32 , . mode_t va_arg,
16 , 32 . , ,
va_mode_t, BSD/OS mode_t .
unpipc.h ( .1):

#ifdef __bsdi__
#define va_mode_t int
#else
#define va_mode_t mode_t
#endif
30 user-execute (S_IXUSR) mode , .


33-34 , , user-execute.


35-40 O_CREAT ,
( ), . mq_open ,
O_CREAT . , - ,
. O_EXCL. EEXIST open
mq_open , O_EXCL. open
EEXIST , , 5.19, O_CREAT .
,
: open, .
, ( ) mq_open . ,
, . ,
( open O_EXCL), .
user-execute , .
, ( O_EXCL ); ,
user-execute.
10.28 10.37.


42-50 ,
: 128 1024 . , , mq_maxmsg mq_msgsize
.
mq_open 5.18. .

5.18. mq_open:

62

//my_pxmsg_mmap/mq_open.
51
/* */
52
msgsize = MSGSIZE(attr->mq_msgsize);
53
filesize = sizeof(struct mymq_hdr) + (attr->mq_maxmsg *
54
(sizeof(struct mymsg_hdr) + msgsize));
55
if (lseek(fd, filesize 1, SEEK_SET) == 1)
56
goto err;
57
if (write(fd, "", 1) == 1)
58
goto err;
59
/* */
60
mptr = mmap(NULL, filesize, PROT_READ | PROT_WRITE,
61
MAP_SHARED, fd, 0);
62
if (mptr == MAP_FAILED)
63
goto err;
64
/* mymq_info{} */
65
if ((mqinfo = mall (sizeof (struct mymq_info))) == NULL)
66
goto err;
67
mqinfo->mqi_hdr = mqhdr = (struct mymq_hdr *) mptr;
68
mqinfo->mqi_magic = MQI_MAGIC;
69
mqinfo->mqi_flags = nonblock;
70
/* */
71
/* */
72
mqhdr->mqh_attr.mq_flags = 0;
73
mqhdr->mqh_attr.mq_maxmsg = attr->mq_maxmsg;
74
mqhdr->mqh_attr.mq_msgsize = attr->mq_msgsize;
75
mqhdr->mqh_attr.mq_curmsgs = 0;
76
mqhdr->mqh_nwait = 0;
77
mqhdr->mqh_pid = 0;
78
mqhdr->mqh_head = 0;
79
index = sizeof(struct mymq_hdr);
80
mqhdr->mqh_free = index;
81
for (i = 0; i < attr->mq_maxmsg 1; i++) {
82
msghdr = (struct mymsg_hdr *) &mptr[index];
83
index += sizeof(struct mymsg_hdr) + msgsize;
84
msghdr->msg_next = index;
85
}
86
msghdr = (struct mymsg_hdr *) &mptr[index];
87
msghdr->msg_next = 0; /* */
88
/* */
89
if ((i = pthread_mutexattr_init(&mattr)) != 0)
90
goto pthreaderr;
91
pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
92
i = pthread_mutex_init(&mqhdr->mqh_lock, &mattr);
93
pthread_mutexattr_destroy(&mattr); /* */
94
if (i != 0)
95
goto pthreaderr:
96
if ((i = pthread_condattr_init(&cattr)) != 0)
97
goto pthreaderr;
98
pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
99
i = pthread_cond_init(&mqhdr->mqh_wait, &cattr);
100
pthread_condattr_destroy(&cattr); /* */
101
if (i != 0)
102
goto pthreaderr;
103
/* , user-execute */
104
if (fchmod(fd, mode) == 1)
105
goto err;
106
close(fd);
107
return((mymqd_t) mqinfo);
108 }

63


51-58 , .
mq_hdr msghdr (. 5.2). lseek
0. ftruncate ( 13.3), ,
.


59-63 mmap.

mq_info
64-66 mq_open mq_inf. .

mq_hdr
67-87 mq_hdr. (mqh_head) ,
(mqh_fr).

88-102 Posix ,
, PTHREAD_PROCESS_SHARED.
pthread_mutexattr_init,
, pthread_mutexattr_setpshared. pthread_mutex_init.
. ,
pthread_ mutexattr_init pthread_condattr_init ( 7.3).

user-execute
103-107 user-execute. ,
. close,
.
5.19 mq_open, .

5.19. mq_open:

//my_pxmsg_mmap/mq_open.
109 exists:
110 /* */
111 if ((fd = open(pathname, O_RDWR)) < 0) {
112
if (errno == ENOENT && (oflag & O_CREAT))
113
goto again;
114 goto err;
115 }
116 /* , */
117 for (i = 0; i < MAX TRIES; i++) {
118
if (stat(pathname, &statbuff) == 1) {
119
if (errno == ENOENT && (oflag & O_CREAT)) {
120
close(fd);
121
goto again;
122
}
123
goto err;
124
}

64

125
if ((statbuff.st_mode & S_IXUSR) == 0)
126
break;
127
sleep(1);
128 }
129 if (i == MAX_TRIES) {
130
errno = ETIMEDOUT;
131
goto err;
132 }
133 filesize = statbuff.st_size;
134 mptr = mmap(NULL, filesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
135 if (mptr == MAP_FAILED)
136
goto err;
137 close(fd);
138 /* mymq_info{} open */
139 if ((mqinfo = malloc(sizeof(struct mymq_info))) == NULL)
140
goto err;
141 rnqinfo->mqi_hdr = (struct mymq_hdr *) mptr;
142 mqinfo->mqi_magic = MQI_MAGIC;
143 mqinfo->mqi_flags = nonblock;
144 return((mymqd_t) mqinfo);
145 pthreaderr:
146 errno = i;
147 err:
148 /* errno */
149 save_errno = errno;
150 if (created)
151
unlink(pathname);
152 if (mptr != MAP_FAILED)
153
munmap(mptr, filesize);
154 if (mqinfo != NULL)
155
free(mqinfo);
156 close(fd);
157 errno = save_errno;
158 return((mymqd_t) 1);
159 }


109-115 , O_CREAT , . ,
. , , open
pocaco (mmap).

, . O_RDONLY,
open mmap,
, . , .
, (O_RDONLY, O_WRONLY, O_RDWR) mq_info .
, mq_receive , mq_info O_WRONLY.


116-132 , ( ,
). stat ( st_mode stat). user-execute
, .
. ,
. lseek 5.18. ,
, exists, open .
, mmap 5.18 (, ), err
unlink. , fstat stat, -
for, . stat, , , , O_CREAT
mq_open, again ( 5.17) .
, open ENOENT.

65

;
mq_info
133-144 , . mq_inf
. .


145-148 err, errno ,
mq_open. , errno
.
mq_cl ose
5.20 mq_close.

5.20. mq_close
//my_pxmsg_mmap/mq_close.
1 #include "unpipc.h"
2 #include "mqueue.h"

*/

3 int
4 mymq_close(mymqd_t mqd)
5 {
6
long msgsize, filesize:
7
struct mymq_hdr *mqhdr;
8
struct mymq_attr *attr;
9
struct mymq_info *mqinfo;
10 mqinfo = mqd;
11 if (mqinfo->mqi_magic != MQI_MAGIC) {
12
errno = EBADF;
13
return(-1);
14 }
15 mqhdr = mqinfo->mqi_hdr;
16 attr = &mqhdr->mqh_attr;
17 if (mymq_notify(mqd, NULL) != 0) /*
18
return(-1);
19 msgsize = MSGSIZE(attr->mq_msgsize);
20 filesize = sizeof(struct mymq_hdr) + (attr->mq_maxmsg *
21
(sizeof(struct mymsg_hdr) + msgsize));
22 if (munmap(mqinfo->mqi_hdr, filesize) == 1)
23
return(-1);
24 mqinfo->mqi_magic = 0; /* */
25 free(mqinfo);
26 return(0);
27 }


10-16 , ,
(mqhdr), ( mq_hdr).


17-18 mq_notify. ,
, .

66

19-25 munmap , mqinfo. ,


, malloc,
mq_magi , .
, mq_close, :
, .
mq_unlink
mqunlink 5.21. , , unlink.

5.21. mq_unlink
//my_pxmsg_mmap/mq_unlink.
1 #include "unpipc.h"
2 #include "mqueue.h"
3
4
5
6
7
8
9

int
mymq_unlink(const char *pathname)
{
if (unlink(pathname) == 1)
return(-1);
return(0);
}

mq_getattr
5.22 mq_getattr, .

5.22. mq_getattr
//my_pxmsg_mmap/mq_getattr.
1 #include "unpipc.h"
2 #include "mqueue.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

int
mymq_getattr(mymqd_t mqd, struct mymq_attr *mqstat)
{
int n;
struct mymq_hdr *mqhdr;
struct mymq_attr *attr;
struct mymq_info *mqinfo;
mqinfo = mqd;
if (mqinfo->mqi_magic != MQI_MAGIC) {
errno = EBADF;
return(-1);
}
mqhdr = mqinfo->mqi_hdr;
attr = &mqhdr->mqh_attr;
if ((n = pthread_mutex_lock(&mqhdr->mqh_lock)) != 0) {
errno = n;
return (-1);
}
mqstat->mq_flags = mqinfo->mqi_flags; /* open */
mqstat->mq_maxmsg = attr->mq_maxmsg; /* */
mqstat->mq_msgsize = attr->mq_msgsize;
mqstat->mq_curmsgs = attr->mq_curmsgs;
pthread_mutex_unlock(&mqhdr->mqh_lock);
return(0);
}

67


17-20 , ,
- .
mq_setattr
5.23 mq_setattr, .


22-27 , -
.

mq_flags
28-31 , , mq_flags, mq_inf.

5.23. mq_setattr
//my_pxmsg_mniap/mq_setattr.
1 #include "unpipc.h"
2 #include "mqueue.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

int
mymq_setattr(mymqd_t mqd. const struct mymq_attr *mqstat,
struct mymq attr *omqstat)
{
int n;
struct mymq_hdr *mqhdr;
struct mymq_attr *attr;
struct mymq_info *mqinfo;
mqinfo = mqd;
if (mqinfo->mqi_magic != MQI_MAGIC) {
errno = EBADF;
return(-1);
}
mqhdr = mqinfo->mqi_hdr;
attr = &mqhdr->mqh_attr;
if ((n = pthread_mutex_lock(&mqhdr->mqh_lock)) ! = 0) {
errno = n;
return(-1);
}
if (omqstat != NULL) {
omqstat->mq_flags = mqinfo->mqi_flags; /* */
omqstat->mq_maxmsg = attr->mq_maxmsg;
omqstat->mq_msgsize = attr->mq_msgsize;
omqstat->mq_curmsgs = attr->mq_curmsgs; /* */
}
if (mqstat->mq_flags & O_NONBLOCK)
mqinfo->mqi flags |= O_NONBLOCK;
else
mqinfo->ntqi_flags &= ~O_NONBLOCK;
pthread_mutex_unlock(&mqhdr->mqh_lock);
return(0);
}

mq_n otify
mq_notify, 5.24,
. ( ) mqh_pid mq_hdr.
. sigevent mqh_event.

68

5.24. mq_notify
//my_pxmsg_mmap/mq_notify.
1 #include "unpipc.h"
2 #include "mqueue.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

int
mymq_notify(mymqd_t mqd, const struct sigevent *notification)
{
int n;
pid_t pid;
struct mymq_hdr *mqhdr;
struct mymq_info *mqinfo;
mqinfo = mqd;
if (mqinfo->mqi magic != MQI_MAGIC) {
errno = EBADF;
return(-1);
}
mqhdr = mqinfo->mqi_hdr;
if ((n = pthread_mutex_lock(&mqhdr->mqh_lock)) != 0) {
errno = n;
return(-1);
}
pid = getpid();
if (notification == NULL) {
if (mqhdr->mqh_pid == pid) {
mqhdr->mqh_pid = 0; /* */
} /* 61 */
} else {
if (mqhdr->mqh_pid != 0) {
if (kill(mqhdr->mqh_pid, 0) != 1 || errno != ESRCH) {
errno = EBUSY;
goto err;
}
}
mqhdr->mqh_pid = pid;
mqhdr->mqh_event = *notification;
}
pthread_mutex_unlock(&mqhdr->mqh_lock);
return(0);
err:
pthread_mutex_unlock(&mqhdr->mqh_lock);
return(-1);
}


20-24 , . ,
.


25-34 - , , , 0 (
null signal). , ,
ESRCH. - , EBUSY.
sigevent.

. ,
.

69

mq_send
5.25 mqsend.

14-29 . ,
.

30-38 , , -
, mq_receive. mq_receive
mqh_nwait, , mq_receive. ,
. SIGEV_SIGNAL sigqueue.
.

sigqueue SI_QUEUE siginfo_t ( 5.7),


. si_code ( SI_MESGQ) .
. 433 IEEE 1996 [8] ,
.


39-48 O_NONBLOCK, EAGAIN.
mqh_wait, , , mq_receive .

EINTR mq_send ,
. , pthread_cond_wait : 0 (
), . , .
5.26 mq_send.
.

5.25. mq_send:
//my_pxmsg_mmap/mq_send.
1 #include "unpipc.h"
2 #include "mqueue.h"
3 int
4 mymq_send(mymqd_t mqd, const char *ptr, size_t len, unsigned int prio)
5 {
6
int n;
7
long index, freeindex;
8
int8_t *mptr;
9
struct sigevent *sigev;
10 struct mymq_hdr *mqhdr;
11 struct mymq_attr *attr;
12 struct mymsg_hdr *msghdr, *nmsghdr, *pmsghdr;
13 struct mymq_info *mqinfo;
14 mqinfo = mqd;
15 if (mqinfo->mqi_magic != MQI_MAGIC) {
16
errno = EBADF;
17
return(-1);
18 }
19 mqhdr = mqinfo->mqi_hdr; /* struct */
20 mptr = (int8_t *) mqhdr; /* */
21 attr = &mqhdr->mqh_attr;
22 if ((n = pthread_mutex_lock(&mqhdr->mqh_lock)) != 0) {
23
errno = n;
24
return(-1);

70

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
32
43
44
45
46
47
48

}
if (len > attr->mq_msgsize) {
errno = EMSGSIZE;
goto err;
}
if (attr->mq_curmsgs == 0) {
if (mqhdr->mqh_pid != 0 && mqhdr->mqh_nwait == 0) {
sigev = &mqhdr->mqh_event;
if (sigev->sigev_notify == SIGEV_SIGNAL) {
sigqueue(mqhdr->mqh_pid, sigev->sigev_signo,
sigev->sigev_value);
}
mqhdr->mqh_pid = 0; /* */
}
} else if (attr->mq_curmsgs >= attr->mq_maxmsg) {
/* 4queue is full */
if (mqinfo->mqi_flags & O_NONBLOCK) {
errno = EAGAIN;
goto err;
}
/* */
while (attr->mq_curmsgs >= attr->mq_maxmsg)
pthread_cond_wait(&mqhdr->mqh_wait, &mqhdr->mqh_lock);
}

5.25. mq_send:
//my_pxmsg_mmap/mq_send.
49 /* nmsghdr */
50 if ((freeindex = mqhdr->mqh_free) == 0)
51
err_dump("mymq_send: curmsgs = %ld; free = 0", attr->mq_curmsgs);
52 nmsghdr = (struct mymsg_hdr *) &mptr[freeindex];
53 nmsghdr->msg_prio = prio;
54 nmsghdr->msg_len = len;
55 memcpy(nmsghdr + 1, ptr, len); /* */
56 mqhdr->mqh_free = nmsghdr->msg_next; /*
*/
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

/* */
index = mqhdr->mqh_head;
pmsghdr = (struct mymsg_hdr *) &(mqhdr->mqh_head);
while (index != 0) {
msghdr = (struct mymsg_hdr *) &mptr[index];
if (prio > msghdr->msg_prio) {
nmsghdr->msg_next = index;
pmsghdr->msg_next = freeindex;
break;
}
index = msghdr->msg_next;
pmsghdr = msghdr;
}
if (index == 0) {
/* */
pmsghdr->msg_next = freeindex;
nmsghdr->msg_next = 0;
}
/* , mq_receive */
if (attr->mq_curmsgs == 0)
pthread_cond_signal(&mqhdr->mqh_wait);

71

78 attr->mq_curmsgs++;
79 pthread_mutex_unlock(&mqhdr->mqh_lock);
80 return(0);
81 err:
82 pthread_mutex_unlock(&mqhdr->mqh lock);
83 return(-1);
84 }


50-52 mq_maxmsg, , mq_curmsgs
mq_maxmsg , .


53-56 nmsghdr , .
msg_hdr, , .



57-74 : .
, ; .
, , mq_receive .
pmsghdr , msg_next.

,
. .

,
mq_receive
75-77 , pthread_cond_signal,
, .
78 mq_curmsgs.
mq_receive
5.27 mq_receive, ,
, .


30-40 O_NONBLOCK, EAGAIN.
mqh_nwait, mq_send ( 5.25) , , .
, mq_send ( 5.26).

mq_receive, mq_send, EINTR, ,


.
5.28 mq_receive. , ,
.

5.27. mq_receive:
//my_pxmsg_mmap/mq_receive.
1 #include "unpipc.h"
2 #include "mqueue.h"
3
4
5
6

ssize_t
mymq_receive(mymqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop)
{
int n;

72

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

long index;
int8_t *mptr;
ssize_t len;
struct mymq_hdr *mqhdr;
struct mymq_attr *attr;
struct mymsg_hdr *msghdr;
struct mymq_info *mqinfo;
mqinfo = mqd;
if (mqinfo->mqi_magic != MQI_MAGIC) {
errno = EBADF;
return(-1);
}
mqhdr = mqinfo->mqi_hdr; /* struct */
mptr = (int8_t *) mqhdr; /* */
attr = &mqhdr->mqh_attr;
if ((n = pthread_mutex_lock(&mqhdr->mqh_lock)) != 0) {
errno = n;
return(-1);
}
if (maxlen < attr->mq_msgsize) {
errno = EMSGSIZE;
goto err;
}
if (attr->mq_curmsgs = 0) { /* */
if (mqinfo->mqi_flags & O_NONBLOCK) {
errno = EAGAIN;
goto err;
}
/* */
mqhdr->mqh_nwait++;
while (attr->mq_curmsgs == 0)
pthread_cond_wait(&mqhdr->mqh_wait, &mqhdr->mqh_lock);
mqhdr->mqh_nwait--;
}

5.28. mq_receive:
//my_pxmsg_mmap/mq_receive.c
41 if ((index = mqhdr->mqh_head) == 0)
42
err_dump("mymq_receive: curmsgs = %ld; head = 0", attr->mq_curmsgs);
43 msghdr = (struct mymsg_hdr *) &mptr[index];
44 mqhdr->mqh_head = msghdr->msg_next; /* */
45 len = msghdr->msg_len;
46 memcpy(ptr, msghdr + 1, len); /* */
47 if (priop != NULL)
48
*priop = msghdr->msg_prio;
49 /* */
50 msghdr->msg_next = mqhdr->mqr_free;
51 mqhdr->mqh_free = index;
52 /* , mq_send */
53 if (attr->mq_curmsgs == attr->mq_maxmsg)
54
pthread_cond_signal(&mqhdr->mqh_wait);
55 attr->mq_curmsgs--;
56 pthread_mutex_unlock(&mqhdr->mqh_lock);
57 return(len);
58 err:
59 pthread_mutex_unlock(&mqhdr->mqh_lock);
60 return(-1);

73

61 }


43-51 msghdr msg_hdr , .
.

,
mq_send
52-54 , pthread_cond_signal ,
mq_send.
5.9.
Posix : ( ) mq_open;
mq_close, mq_unlink. mq_send,
mq_receive. mq_getattr mq_setattr, mq_notify
. ( ),
mq_receive .
mq_notify, Posix, SIGMIN SIGMAX.
SA_SIGINFO ,
( ).
, Posix 500 ,
, Posix.
; 10 Posix.

1. 5.4, , attr mq_open ;


: mq_maxmsg mq_msgsize. , ,
?
2. 5.8 , mq_notify. ,
. ?
3. 5.8 , . mq_notify
. , . ?
4. , printf 5.14?
5. 5.4 : mq_open 30 (sleep).
mq_open 30 , mq_close. ,
( ) , , 10 . ,
, . 30- ps
. mq_open. ?
6. memcpy 5.26, ?
7. , 4.4.
?
8. 5.20?
9. Posix , . ?
10. main 5.12? ?
?
11. PTHREAD_PROCESS_SHARED .
5.8 , Posix ( 10) .
12. Posix 5.8 , SIGEV_THREAD.
6
System V
6.1.
System V .
( 3.5) , .
Posix, System V .
, :

struct msqid_ds {
struct ipc_perm msg_perm; /* : 3.3 */
struct msg *msg_first; /* */
struct msg *msg_last; /* */
msglen_t msg_cbytes; /* */
msgqnum_t msg_qnum; /* */
msglen_t msg_qbytes; /* */
pid_t msg_lspid;
/* (pid) ,
msgsnd(); */
pid_t msg_lrpid; /* pid msgrcv(); */
time_t msg_stime; /* */
time_t msg_rtime; /* */
time_t msg_ctime; /* msgctl(),
*/
};

74


Unix 98 msg_first, msg_last msg_cbytes. ,
System V. , ,
msg_first msg_last. , , .
, , . 6.1. 1, 2
3 100, 200 300 .
, System V,
4.2 .

. 6.1. system V
6.2. msgget
msgget:

#include
int msgget(key_t key, int oflag);
/* , 1
*/
, msg
. , ftok
IPC_PRIVATE, . 3.1.
oflag -, . 3.3. IPC_CREAT
IPC_CREAT | IPC_EXCL , . 3.2.
msqid_ds:
uid cuid msg_perm , gid cgid
;
-, oflag, msg_perm.mode;
msg_qnum, msg_lspid, msg_lrpid, msg_stime msg_rtime 0;
msg_ctime ;
msg_qbytes .
6.3. msgsnd
msgget msgsnd.

#include
int msgsnd(int msqid, const void *ptr, size_t length, int flag);
/* 0 ; 1 */
msqid , msgget. ptr ,
:

struct msgbuf {
long mtype; /* , > 0 */
char mtext[1]; /* */
};
, msgrcv,
.
mtext msgbuf ; .
, . .
, ptr long, ,
( 0 ).
msgbuf, (1 ) .
( , ),
(, ) .
, .
, , 16- , 8- ,
:

#define MY_DATA 8
typedef struct my_msgbuf {
long mtype; /* */
int16_t mshort; /* */
char mchar[MY_DATA];
} Message;
length msgsnd . , (
long). 0. sizeof(Message) sizeof(long).
flag 0, IPC_NOWAIT. msgsnd:
, . , :

75

( msg_qbytes msqid_ds);
.
IPC_NOWAIT, msgsnd EAGAIN. IPC_NOWAIT
, , , :
;
msqid ( EIDRM);
( EINTR).
6.4. msgrcv
msgrcv.

#include
ssize_t msgrcv(int msqid, void *ptr, size_t length, long type, int flag);
/* , 1 */
ptr , . msgsnd, long (. 4.13),
.
length , ptr. ,
. long .
type , :
type 0, ( 0 );
0, , ;
, , type.
, . 6.1. :
100 1;
200 2;
300 3.
6.1 , type.

6.1. type

type
0
100
200
300
-100
-200
-300


100
100
200
300
100
100
100

flag , , . IPC_NOWAIT,
msgrcv ENOMSG. ,
:
;
msqid ( EIDRM);
( EINTR).
flag MSG_NOERROR. , (
length), . ,
length E2BIG.
msgrcv . ,
(long), ptr.
6.5. msgctl
msgctl :

#include
int msgctl(int msqid, int cmd, struct msqid_ds *buff);
/* 0 , 1 */
( cmd) :
IPC_RMID msqid . , , .
3.2. .
IPC_SET msqid_ds ,
buff: msg_perm.uid, msg_perm.gid, msg_perm.mode, msg_qbytes.
IPC_STAT ( buff) msqid_ds .

6.1 , 1 , msgctl
IPC_STAT, ipcs, system, , msgctl IPC_RMID.

6.1. [1]
msgctl IPC_STAT
//svmsg/ctl.
1 #include "unpipc.h"

76

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

int
main(int argc, char **argv)
{
int msqid;
struct msqid_ds info;
struct msgbuf buf;
msqid = Msgget(IPC_PRIVATE, SVMSG_MODE | IPC_CREAT);
buf.mtype = 1;
buf.mtext[0] = 1;
Msgsnd(msqid, &buf, 1, 0);
Msgctl(msqid, IPC_STAT, &info);
printf("read-write: *03o, cbytes = %lu, qnum = %lu, qbytes = %lu\n",
info.msg_perm.mode & 0777, (ulong_t) info.msg_cbytes,
(ulong_t) info.msg_qnum, (ulong_t) info.msg_qbytes);
system("ipcs q");
Msgctl(msqid, IPC_RMID, NULL);
exit(0);
}

1 , msgbuf .
:

solaris %ctl
read-write: 664, cbytes = 1, qnum = 1, qbytes = 4096
IPC status from as of MOn Oct 20 15:36:49 1997
T ID
Key
MODE
OWNER
GROUP
Message Queues:
q 1150 00000000 rw-rw-r-- rstevens other1
. IPC_PRIVATE, 3.2.
4096 . 1 msg_cbytes
1, (long), .
6.6.
System V ,
.
msgcreate
6.2 msgcreate, .
9-12 e IPC_EXCL.
16 , , ftok.
msgget.

6.2. System V
//svmsg/msgcreate.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

int
main(int argc, char **argv)
{
int c, oflag, mqid;
oflag = SVMSG_MODE | IPC_CREAT;
while ((c = Getopt(argc, argv, "e")) != 1) {
switch (c) {
case 'e':
oflag |= IPC_EXCL;
break;
}
}
if (optind != argc 1)
err_quit("usage: msgcreate [ e ] ");
mqid = Msgget(Ftok(argv[optind], 0), oflag);
exit(0);
}

77

msgsn d
msgsnd 6.3. .
msgbuf , ( ) ,
calloc. .

6.3.
System V
//svmsg/msgsnd.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

int
main(int argc, char **argv)
{
int mqid;
size_t len;
long type;
struct msgbuf *ptr;
if (argc != 4)
err_quit("usage: msgsnd <#bytes> ");
len = atoi(argv[2]);
type = atoi(argv[3]);
mqid = Msgget(Ftok(argv[1], 0), MSG_W);
ptr = Calloc(sizeof(long) + len, sizeof(char));
ptr->mtype = type;
Msgsnd(mqid, ptr, len, 0);
exit(0);
}

msgrcv
6.4 msgrcv, . n,
, t msgrcv.
2 ( 6.10),
.

6.4.
System V
//svmsg/msgrcv.c
1 #include "unpipc.h"
2 #define MAXMSG (8192 + sizeof(long))
3 int
4 main(int argc, char **argv)
5 {
6
int c, flag, mqid;
7
long type;
8
ssize_t n;
9
struct msgbuf *buff;
10 type = flag = 0;
11 while ((c = Getopt(argc, argv, "nt:")) != 1) {
12
switch (c) {
13
case 'n':
14
flag |= IPC_NOWAIT;
15
break;
16
case 't':
17
type = atol(optarg);
18
break;
19
}

78

20 }
21 if (optind != argc 1)
22
err_quit("usage: msgrcv [ n ] [ t type ] ");
23 mqid = Msgget(Ftok(argv[optind], 0), MSG_R);
24 buff = Malloc(MAXMSG);
25 n = Msgrcv(mqid, buff, MAXMSG, type, flag);
26 printf("read %d bytes, type = %ld\n", n, buff->mtype);
27 exit(0);
28 }
msgrmid
msgctl IPC_RMID, 6.5.

6.5. System V
//svmsg/msgrmid.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11

int
main(int argc, char **argv)
{
int mqid;
if (argc != 2)
err_quit("usage: msgrmid ");
mqid = Msgget(Ftok(argv[1], 0), 0);
Msgctl(mqid, IPC_RMID, NULL);
exit(0);
}

. :

solaris % msgcreate /tmp/no/such/file


ftok error for pathname "tmp/no/such/file" and id 0: No such file or directory
solaris % touch /trap/test1
solaris % msgcreate /tmp/test1
solaris % msgsnd /tmp/test1 1 100
solaris % msgsnd /tmp/test1 2 200
solaris % msgsnd /tmp/test1 3 300
solaris % ipcs qo
IPC status from as of Sat Jan 10 11:25:45 1998
T ID KEY
MODE
OWNER
GROUP CBYTES QNUM
Message Queues:
q 100 00000113e rw-r--r-- rstevens other1 6
3
, . , ,
ftok, . /tmp/test1 .
1, 2 3 100, 200 300 ( . 6.1). ipcs ,
3 6 .
type msgrcv :

solaris % msgrcv t 200 /tmp/test1


read 2 bytes, type = 200
solaris % msgrcv t -300 /tmp/test1
read 1 bytes, type = 100
solaris % msgrcv /tmp/test1
read 3 bytes, type = 300
solaris % msgrcv n /tmp/test1
msgrcv error: No message of desired type
200, , 300,
. msgrcv IPC_NOWAIT.
, , ?

solaris % ipcs qo
IPC status from as of Sat Jan 10 11:37:01 1998
T ID KEY
MODE
OWNER
GROUP CBYTES QNUM
Message Queues:

79

q 100 0x0000113e rw-r--r-- rstevens other1 0


0
solaris % msgsnd /tmp/test1 1 100
solaris % msgrcv t 999 /temp/test1
^?
solaris % msgrcv n t999/tmp/test1
msgrcv error: No message of desired type
solaris % grep desired /usr/include/sys/errno.h
#define ENOMSG 35 /* No message of desired type */
solaris % msgrmid /tmp/test1
ipcs, , , 1 100.
999, ( msgrcv), .
. n, , ,
ENOMSG. msgrmid.

solaris % ipcrm q 100


,

solaris % ipcrm Q 0x113e


.
msgrcvid
, System V msgget: , ,
, ipcs, . 6.6
msgrcv 6.4.
msgget. ,
.

6.6.
System V
//svmsg/msgrcvid.c
1 #include "unpipc.h"
2 #define MAXMSG (8192 + sizeof(long))
3
4
5
6
7
8
9
10
11
12
13
14
15
16

int
main(int argc, char **argv)
{
int mqid;
ssize_t n;
struct msgbuf *buff;
if (argc != 2)
err_quit("usage: msgrcvid ");
mqid = atoi(argv[1]);
buff = Maloc(MAXMSG);
n = Msgrcv(mqid, buff, MAXMSG, 0, 0);
printf("read %d bytes, type = %ld\n", n, buff->mtype);
exit(0);
}

solaris % touch /tmp/testid


solaris % msgcreate /tmp/testid
solaris % msgsnd /tmp/testid4 400
solaris % ipcs qo
IPC status from as of Wed Mar 25 09:48:28 1998
T ID KEY
MODE
OWNER
GROUP CBYTES QNUM
Message Queues:
q 150 0x0000118a rw-r--r-- rstevens other1 4
1
solaris % msgrcvid 150
read 4 bytes, type = 400
(150) ipcs, msgrcvid .
System V ( 11.1) System V ( 14.1).
6.7. -
- 4.2 .
, .

80

svmsg.h 6.7.
.

6.7. svmsg.h
-,

//svmsgcliserv/svmsg.h
1 #include "unpipc.h"
2 #define MQ_KEY1 1234L
3 #define MQ_KEY2 2345L
main 6.8. , , - ,
IPC_EXCL. server 4.16. mesgsend mesgrecv,
.

6.8. main -,

//svmsgcliserv/server_main.
1 #include "svmsg.h"
2
3
4
5
6
7
8
9
10
11

void server(int, int);


int
main(int argc, char **argv)
{
int readid, writeid;
readid = Msgget(MQ_KEY1, SVMSG_MODE | IPC_CREAT);
writeid = Msgget(MQ_KEY2, SVMSG_MODE | IPC_CREAT);
server(readid, writeid);
exit(0);
}

6.9. main -,

//svmsgcliserv/client_main.
1 #include "svmsg.h"
2 void client(int, int);
3
4
5
6
7
8
9
10
11
12
13
14
15

int
main(int argc, char **argv)
{
int readid, writeid;
/* assumes server has created the queues */
writeid = Msgget(MQ_KEY1, 0);
readid = Msgget(MQ_KEY2, 0);
client(readid, writeid);
/* now we can delete the queues */
Msgctl(readid, IPC_RMID. NULL);
Msgctl(writeid, IPC_RMID, NULL);
exit(0);
}

6.9 main -. client


4.15. : mesg_send mesg_recv, .
client, server , 4.12.
mesg_send mesg_recv. , 4.13 4.14, write read

81

FIFO, . 6.10 6.11


. , ,
FIFO, .

6.10. mesg_send,
System V
//svmsgcliserv/mesg_send.
1 #include "mesg.h"
2
3
4
5
6

ssize_t
mesg_send(int id, struct mymesg *mptr)
{
return(msgsnd(id, &(mptr->mesg_type), mptr->mesg_len, 0));
}

6.11. mesg_recv,
System V
//svmsgcliserv/mesg_recv.
1 #include "mesg.h"
2
3
4
5
6
7
8
9

ssize_t
mesg_recv(int id, struct mymesg *mptr)
{
ssize_t n;
n = msgrcv(id, &(mptr->mesg_type), MAXMESGDATA, mptr->mesg_type, 0);
mptr->mesg_len = n; /* */
return(n); /* 1 , 0 , >0 */
}

6.8.
type :
1. type , .
, , ,
. , , ,
.
2. type . ,
(FIFO). FIFO , .
System V . , msgrcv
IPC_NOWAIT .
:
- -. FIFO,
IPC , IPC .
, type ( ).

. 6.2.

82

: . 1, ,
. ,
, . PID
type msgrcv. . 6.2
.

IPC (deadlock).
( ) , .
msgsnd, . , , ,
.
, .
: 1 , ,
. PID ,
4.8.
6.12 main . svmsg.h 6.7.
( , ).
server.

6.12. main
//svmsgmpx1q/server_main.
1 #include "svmsg.h"
2 void server(int, int);
3
4
5
6
7
8
9
10

int
main(int argc, char **argv)
{
int msqid;
msqid = Msgget(MQ_KEY1, SVMSG_MODE | IPC_CREAT);
server(msqid, msqid); /* */
exit(0);
}

server . 6.13. 4.10


FIFO, , , 4.16,
mesg_send mesg_recv. , , ,
, . ,
. (. 4.9).
6.14 main . , .
client, 6.15, .
4.11 4.15. ,
mesg_send mesg_recv. , , mesg_recv,
.
client server mesg_send mesg_recv 6.9 6.11.

6.13. server
//svmsgmpx1q/server.c
1 #include "mesg.h"
2 void
3 server(int readfd, int writefd)
4 {
5
FILE *fp;
6
char *ptr;
7
pid_t pid;
8
ssize_t n;
9
struct mymesg mesg;
10 for (;;) {
11
/* IPC */
12
mesg.mesg_type = 1:
13
if ((n = Mesg_recv(readfd, &mesg)) == 0) {
14
err_msg("pathname missing");
15
continue;
16
}
17
mesg.mesg_data[n] = '\0'; /* */

83

18
if ((ptr = strchr(mesg.mesg_data, ' ')) == NULL) {
19
err_msg("bogus request: %s", mesg.mesg_data);
20
continue;
21
}
22
*ptr++ =0; /* ptr = */
23
pid = atol(mesg.mesg_data);
24
mesg.mesg_type = pid; /* */
25
if ((fp = fopen(ptr, "r")) == NULL) {
26
/* 4error: must tell client */
27
snprintf(mesg.mesg_data + n, sizeof(mesg.mesg_data) n,
28
": can't open. %s\n", strerror(errno));
29
mesg.mesg_len strlen(ptr);
30
memmove(mesg.mesg_data, ptr, mesg.mesg_len);
31
Mesg_send(writefd, &mesg);
32
} else {
33
/* , */
34
while (Fgets(mesg.mesg_data, MAXMESGDATA, fp) != NULL) {
35
mesg.mesg_len = strlen(mesg.mesg_data);
36
Mesg_send(writefd, &mesg);
37
}
38
Fclose(fp);
39
}
40
/* */
41
mesg.mesg_len = 0;
42
Mesg_send(writefd, &mesg);
43 }
44 }

6.14. main
//svmsgmpx1q/client_main.c
1 #include "svmsg.h"
2 void client(int, int);
3
4
5
6
7
8
9
10
11

int
main(int argc, char **argv)
{
int msqid;
/* */
msqid = Msgget(MQ_KEY1, 0);
client(msqid, msqid); /* */
exit(0);
}

6.15. client
//svmsgmpx1q/client.
1 #include "mesg.h"
2
3
4
5
6
7
8
9

void
client(int readfd, int writefd)
{
size_t len;
ssize_t n;
char *ptr;
struct mymesg mesg;
/* */

84

10 snprintf(mesg.mesg_data, MAXMESGDATA. "%ld ", (long) getpid());


11 len = strlen(mesg.mesg_data);
12 ptr = mesg.mesg_data + len;
13 /* */
14 Fgets(ptr, MAXMESGDATA len, stdin);
15 len = strlen(mesg.mesg_data);
16 if (mesg.mesg_data[len-1] == '\n')
17
len--; /* fgets() */
18 mesg.mesg_len = len;
19 mesg.mesg_type = 1;
20 /* PID IPC */
21 Mesg_send(writefd, &mesg);
22 /* IPC, stdout */
23 mesg.mesg_type = getpid();
24 while ((n = Mesg_recv(readfd, &mesg)) > 0)
25
Write(STDOUT_FILENO, mesg.mesg_data, n);
26 }
:
, ,
. . 6.3 .

. 6.3.

, IPC_PRIVATE.
, .
: .

, (
).
:
mesg.h ( 4.12);
svmsg.h ( 6.7);
main ( 6.12);
mesg_send ( 4.13).
main 6.16; 6.14.
(MQ_KEY1) IPC_PRIVATE. client
( 6.17). .

6.16. main
//svmsgmpxnq/client_main.
1 #include "svmsg.h"
2
3
4
5

void client(int, int);


int
main(int argc, char **argv)
{

85

6
int readid, writeid;
7
/* */
8
writeid = Msgget(MQ_KEY1, 0);
9
/* */
10 readid = Msgget(IPC_PRIVATE, SVMSG_MODE | IPC_CREAT);
11 client(readid, writeid);
12 /* */
13 Msgctl(readid, IPC_RMID, NULL);
14 exit(0);
15 }

6.17. client
//svmsgmpxnq/client.
1 #include "mesg.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

void
client(int readid, int writeid)
{
size_t len;
ssize_t n;
char *ptr;
struct mymesg mesg;
/* */
snprintf(mesg.mesg_data, MAXMESGDATA, "%d ", readid);
len = strlen(mesg.mesg_data);
ptr = mesg.mesg_data + len;
/* */
Fgets(ptr, MAXMESGDATA len, stdin);
len = strlen(mesg.mesg_data);
if (mesg.mesg_data[len-1] == '\n')
len--; /* fgets() */
mesg.mesg_len = len;
mesg.mesg_type = 1;
/* */
Mesg_send(writeid, &mesg);
/* stdout */
while ((n = Mesg_recv(readid, &mesg)) > 0)
Write(STDOUT_FILENO, mesg.mesg_data, n);
}

6.17 client. 6.15,


. mesg 1,
, .
6.19 server. 6.13 , ,
fork.

SIGCHLD
10 , -. 5.9 5.10 [24]
. SIGCHLD, sig_chld ( 6.18)
.
12-18 mesg_recv, .
25-45 fork ,
, . fopen , ,
, .
- SIGCHLD 6.18. 5.11 [24].

6.18. SIGCHLD,
waitpid
86

//svmsgmpxnq/sigchldwaitpid.
1 #include "unpipc.h"
2
3
4
5
6
7
8
9

void
sig_chld(int signo)
{
pid_t pid;
int stat;
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0);
return;
}

waitpid ,
. . ,
( mesg_recv, 6.9). msgrcv
. EINTR, 5.9 [24].
, - Mesg_recv, 6.20.
EINTR mesg_recv ( msgrcv), , ,
mesg_recv.

6.19. server
//svmsgmpxnq/server.c
1 #include "mesg.h"
2 void
3 server(int readid, int writeid)
4 {
5
FILE *fp;
6
char *ptr;
7
ssize_t n;
8
struct mymesg mesg;
9
void sig_chld(int);
10 Signal(SIGCHLD, sig_chld);
11 for (;;) {
12
/* */
13
mesg.mesg_type = 1;
14
if ((n = Mesg_recv(readid, &mesg)) == 0) {
15
err_msg("pathname missing");
16
continue;
17
}
18
mesg.mesg_data[n] = 40'; /* */
19
if ((ptr = strchr(mesg.mesg_data, ' ')) = NULL) {
20
err_msg("bogus request: %s", mesg.mesg_data);
21
continue;
22
}
23
*ptr++ = 0; /* ptr = */
24
writeid = atoi(mesg.mesg_data);
25
if (Fork() == 0) { /* */
26
if ((fp = fopen(ptr, "r")) == NULL) {
27
/* : */
28
snprintf(mesg.mesg_data + n, sizeof(mesg.mesg_data) n,
29
": can't open, %s\n", strerror(errno));
30
mesg.mesg_len = strlen(ptr);
31
memmove(mesg.mesg_data, ptr, mesg.mesg_len);
32
Mesg_send(writeid, &mesg);
33
} else {
34
/* , */
35
while (Fgets(mesg.mesg_data, MAXMESGDATA, fp) != NULL) {
36
mesg.mesg_len = strlen(mesg.mesg_data);
37
Mesg_send(writeid, &mesg);

87

38
}
39
Fclose(fp);
40
}
41
/* , */
42
mesg.mesg_len = 0;
43
Mesg_send(writeid, &mesg);
44
exit(0); /* */
45
}
46
/* */
47 }
48 }

6.20. - Mesg_recv,

//svmsgmpxnq/mesg_recv.
10 ssize_t
11 Mesg_recv(int id, struct mymesg *mptr)
12 {
13 ssize_t n;
14 do {
15
n = mesg_recv(id, mptr);
16 } while (n == 1 && errno == EINTR);
17 if (n == 1)
18
err_sys("mesg_recv error");
19 return(n);
20 }
6.9. select poll
System V , , .
select poll ( 6 [24]).

Unix, AIX ( IBM), select System V,


. AIX.
, , IPC.
XTI ([24]) , select poll.
FIFO , .
: ,
msgrcv. msgrcv, .
select . ,
: msgrcv,
. ,
( 12.5).

5.12 Posix, fork. Posix


, .
System V , , msgrcv.
System V
(, MSG_PEEK recv, recvfrom, recvmsg [24, . 356]).
, - ( select) ,
peek msgrcv 1 ,
.
6.10. ,
3.8, oae. . 6.2 oae
. System V , .
6.2.

msgmax
msgmnb
msgmni
msgtlq

DUnix 4.0B Solaris 2.6


8192
2048
16384
4096
64
50
40
40

, .
, , ( ) ( 3.8).

6.21 , , . 6.2.

88

6.21.
System V
//svmsg/limits.c
1 #include "unpipc.h"
2 #define MAX_DATA 64*1024
3 #define MAX_NMESG 4096
4 #define MAX_NIDS 4096
5 int max_mesg;
6
7
8
9

struct mymesg {
long type;
char data[MAX_DATA];
} mesg;

10 int
11 main(int argc, char **argv)
12 {
13 int i, j, msqid, qid[MAX_NIDS];
14 /* */
15 msqid = Msgget(IPC_PRIVATE, SVMSG_MODE | IPC_CREAT);
16 mesg.type = 1;
17 for (i = MAX_DATA; i > 0; i = 128) {
18
if (msgsnd(msqid, &mesg, i, 0) == 0) {
19
printf("maximum amount of data per message = %d\n", i);
20
max_mesg = i;
21
break;
22
}
23
if (errno != EINVAL)
24
err_sys("msgsnd error for length %d", i);
25 }
26 if (i == 0)
27
err_quit("i == 0");
28 Msgct(lmsqid, IPC_RMID, NULL);
29 /* */
30 mesg.type = 1;
31 for (i = 8; i <= max_mesg; i *= 2) {
32
msqid = Msgget(IPC_PRIVATE, SVMSG_MODE | IPC_CREAT);
33
for (j = 0; j < MAX_NMESG; j++) {
34
if (msgsnd(msqid, &mesg, i, IPC_NOWAIT) != 0) {
35
if (errno == EAGAIN)
36
break;
37
err_sys("msgsnd error, i = %d, j = %d", i, j);
38
break;
39
}
40
}
41
printf("%d %d-byte messages were placed onto queue,", j, i);
42
printf(" %d bytes total\n". i*j);
43
Msgctl(msqid, IPC_RMID, NULL);
44 }
45 /* */
46 mesg.type = 1;
47 for (i = 0; i <= MAX_NIDS; i++) {
48
if ((qid[i] = msgget(IPC_PRIVATE, SVMSG_MODE | IPC_CREAT)) == 1) {
49
printf("%d identifiers open at once\n", i);
50
break;
51
}

89

52 }
53 for (j = 0; j < i; j++)
54
Msgctl(qid[j], IPC_RMID, NULL);
55 exit(0);
56 }


14-28 , 65 536 ,
, 65 408, .., msgsnd .


?
29-44 8- , .
( ) 16- . ,
. ,
, .


?
45-54 .
, msgget.
Solaris 2.6, Digital Unix 4.0B, . 6.2 :

solaris % limits
maximum amount of data per message = 2048
40 8-byte messages were placed on queue, 320 bytes total
40 16-byte messages were placed on queue, 640 bytes total
40 32-byte messages were placed on queue, 1280 bytes total
40 64-byte messages were placed on queue, 2560 bytes total
32 128-byte messages were placed on queue, 4096 bytes total
16 256-byte messages were placed on queue, 4096 bytes total
8 512-byte messages were placed on queue, 4096 bytes total
4 1024-byte messages were placed on queue, 4096 bytes total
2 2048-byte messages were placed on queue, 4096 bytes total
50 identifiers open at once
alpha % limits
maximum amount of data per message = 8192
40 8-byte messages were placed on queue, 320 bytes total
40 16-byte messages were placed on queue, 640 bytes total
40 32-byte messages were placed on queue, 1280 bytes total
40 64-byte messages were placed on queue, 2560 bytes total
40 128-byte messages were placed on queue, 5120 bytes total
40 256-byte messages were placed on queue, 10240 bytes total
32 512-byte messages were placed on queue, 16384 bytes total
16 1024-byte messages were placed on queue, 16384 bytes total
8 2048-byte messages were placed on queue, 16384 bytes total
4 4096-byte messages were placed on queue, 16384 bytes total
2 8192-byte messages were placed on queue, 16384 bytes total
63 identifiers at once
, Digital Unix 4.0 63 , 64, . 6.2, ,
.
6.11.
System V Posix.
Posix, System V.
Posix System V . Posix
. ,
select poll .

90


1. . 6.2 , , 1?
2. . 6.2, , ?
. 6.3?
3. Posix 5.8 System V
.
3

7

7.1.
.
. (mutual exclusion mutex)
(conditional variables) .
Posix.1 ,
. Posix
, , .

Posix, Unix 98 (. . 1.3).


-, .
, , , , ,
(
). , , 10.
7.2. :
(mutex) . (critical region),
( ) (
). :

_mutex();

_mutex();
, ,
, .
Posix pthread_mutex_t. - ,
PTHREAD_MUTEX_INITIALIZER:

static pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;


(, mall)
, pthread_ mutex_init, 7.7.

, ,
0, . .
:

#include
int pthread_mutex_lock(pthread_mutex_t *mptr);
int pthread_mutex_trylock(pthread_mutex_t *mptr);
int pthread_mutex_unlock(pthread_mutex_t *mptr);
/* 0 ,
*/
, , pthread_mutex_lock
, a pthread_mutex_trylock ( ) EBUSY.

, ? ,
1003.1b-1993, . , ,
( , ) . 5.5 [3]
Posix.1 .
, , .
.
. ,
, , , , , .
, . .
7.3. -
.
. ( ) , .
IPC.
Unix. ,

grep pattern chapters.* | wc -l


. grep (), a wc ( ).
IPC. , write
read . ( ),
write, . ( ),
read, .
; , .
Posix System V IPC ,
.
IPC , , -
. . . 7.1.

91

- -. buff
( ). buff[0] 0, buff [1] 1 ..
, .
-. -
, . 7.1 main .

. 7.1.

7.1. [1] main


//mutex/prodcons2.
1 #include "unpipc.h"
2 #define MAXNITEMS 1000000
3 #define MAXNTHREADS 100
4 int nitems; /* */
5 struct {
6
pthread_mutex_t mutex;
7
int buff[MAXNITEMS];
8
int nput;
9
int nval;
10 } shared = {
11 PTHREAD_MUTEX_INITIALIZER
12 };
13 void *produce(void *), *consume(void *);
14 int
15 main(int argc, char **argv)
16 {
17 int i, nthreads, count[MAXNTHREADS];
18 pthread_t tid_produce[MAXNTHREADS], tid_consume;
19 if (argc != 3)
20
err_quit("usage: prodcons2 <#items> <#threads>");
21 nitems = min(atoi(argv[1]), MAXNITEMS);
22 nthreads = min(atoi(argv[2]), MAXNTHREADS);
23 Set_concurrency(nthreads);
24 /* - */
25 for (i = 0; i < nthreads; i++) {
26
count[i] = 0;
27
Pthread_create(&tid_produce[i], NULL, produce, &count[i]);
28 }
29 /* */
30 for (i = 0; i < nthreads; i++) {
31
Pthread_join(tid_produce[i], NULL);
32
printf("count[%d] = %d\n", i, count[i]);
33 }
34 /* - */

92

35 Pthread_create(&tid_consume, NULL, consume, NULL);


36 Pthread_join(tid_consume, NULL);
37 exit(0);
38 }

4-12 . shared ,
, . nput buff,
, a nval , (0, 1, 2 ..).
, -.

, (
, , ), , . .
, , , . , ,
( mq_hdr 5.16),
. , .


19-22 , ,
-.


23 set_concurrency ( ) . Solaris 2.6
thr_setconcurrency, , , -
. Solaris, . Digital Unix 4.0B set_concurrency
, .

Unix 98 pthread_setconcurrency, . ,
( pthread_create) .
-- (many-to-few), (two-level) --N (M-to-N). 5.6 [3]
.

-
24-28 -, produce. tid_produce.
- count. 0,
1 . ,
, .

,

29-36 -, ,
-. ( )
. , . 7.2 produce consume.

7.2. produce consume


//mutex/prodcons2.
39 void *
40 produce(void *arg)
41 {
42 for (;;) {
43
Pthread_mutex_lock(&shared.mutex);
44
if (shared.nput >= nitems) {
45
Pthread_mutex_unlock(&shared.mutex);
46
return(NULL); /* , */

93

47
}
48
shared.buff[shared.nput] = shared.nval;
49
shared.nput++;
50
shared.nval++;
51
Pthread_mutex_unlock(&shared.mutex);
52
*((int *) arg) += 1;
53 }
54 }
55
56
57
58
59
60
61
62
63
64

void *
consume(void *arg)
{
int i;
for (i = 0; i < nitems; i++) {
if (shared.buff[i] != i)
printf("buff[%d] = %d\n", i, shared.buff[i]);
}
return(NULL);
}


42-53 ( )

if (shared.nput >= nitems)


, :

shared.buff[shared.nput] = shared.nval;
shared.nput++;
shared.nval++;
, . ,
count ( arg) , ( count
main). .
, .


59-62 .
, , - ,
.
-,
, :

solaris % prodcons2 1000000 5


count[0] = 167165
count[1] = 249891
count[2] = 194221
count[3] = 191815
count[4] = 196908
, set_concurrency, Solaris 2.6 count[0] 1000000,
.
, , .
buff[i], i. , ,
.
7.4.
, , .
, .
poa 7.1, ,
. , ,
.
7.3 main. ( main)
7.1.

7.3. main:

94

//mutex/prodcons3.c
14 int
15 main(int argc, char **argv)
16 {
17 int i, nthreads, count[MAXNTHREADS];
18 pthread_t tid_produce[MAXNTHREADS], tid_consume;
19 if (argc != 3)
20
err_quit("usage: prodcons3 <#items> <#threads>");
21 nitems = min(atoi(argv[1]), MAXNITEMS);
22 nthreads = min(atoi(argv[2]), MAXNTHREADS);
23 /* */
24 Set_concurrency(nthreads + 1);
25 for (i = 0; i < nthreads; i++) {
26
count[i] = 0;
27
Pthread_create(&tid_produce[i], NULL, produce, &count[i]);
28 }
29 Pthread_create(&tid_consume, NULL, consume, NULL);
30 /* */
31 for (i = 0; i < nthreads; i++) {
32
Pthread_join(tid_produce[i], NULL);
33
printf("count[%d] = %d\n", i, count[i]);
34 }
35 Pthread_join(tid_consume, NULL);
36 exit(0);
37 }
24 , -, .
25-29 - -.
produce 7.2 . 7.4 consume,
consume_wait.

7.4. consume consume_wait


//mutex/prodcons3.
54 void
55 consume wait(int i)
56 {
57 for (;;) {
58
Pthread_mutex_lock(&shared.mutex);
59
if (i < shared.nput) {
60
Pthread_mutex_unlock(&shared.mutex);
61
return; /* */
62
}
63
Pthread_mutex_unlock(&shared.mutex);
64 }
65 }
66
67
68
69
70
71
72
73
74
75
76

void *
consume(void *arg)
{
int i;
for (i = 0; i < nitems; i++) {
consume_wait(i);
if (shared.buff[i] != i)
printf("buff[%d] = %d\n", i, shared.buff[i]);
}
return(NULL);
}

95


71 consume consume_wait .


57-64 consume_wait , i- .
i nput. , nput
.
, . , 7.4,
, . (spinning polling)
.
, , .
- , , - .
7.5. :
, . ,
. pthread_cond_t. :

#include
int pthread_cond_wait(pthread_cond_t *cptr, pthread_m_tex_t *mptr);
int pthread_cond_signal(pthread_cond_t *cptr);
/* 0 ,
*/
signal Unix SIGxxx.
, .
. pthread_cond_wait -
.
, . 7.5
.



7-13 nput rival mutex, put. .
14-20 , nready, , .
PTHREAD_ COND_INITIALIZER.
main 7.3 .

7.5. :

//mutex/prodcons6.c
1 #include "unpipc.h"
2 #define MAXNITEMS 1000000
3 #define MAXNTHREADS 100
4
5
6

/* */
int nitems; /* */
int buff[MAXNITEMS];

7 struct {
8
pthread_mutex_t mutex;
9
int nput; /* */
10 int nval; /* */
11 } put = {
12 PTHREAD_MUTEX_INITIALIZER
13 };
14 struct {
15 pthread_mutex_t mutex:
16 pthread_cond_t cond;

96

17 int nready; /* */
18 } nready = {
19 PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER
20 };
produce consume . 7.6.

7.6. produce consume


//mutex/prodcons6.c
46 void *
47 produce(void *arg)
48 {
49 for (;;) {
50
Pthread_mutex_lock(&put.mutex);
51
if (put.nput >= nitems) {
52
Pthread_mutex_unlock(&put.mutex);
53
return(NULL); /* , */
54
}
55
buff[put.nput] = put.nval;
56
put.nput++;
57
put.nval++;
58
Pthread_mutex_unlock(&put.mutex);
59
Pthread_mutex_lock(&nready.mutex):
60
if (nready.nready == 0)
61
Pthread_cond_signal(&nready.cond);
62
nready.nready++;
63
Pthread_mutex_unlock(&nready.mutex);
64
*((int *) arg) += 1;
65 }
66 }
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

void*
consume(void *arg)
{
int i;
for (i = 0; i < nitems; i++) {
Pthread_mutex_lock(&nready.mutex);
while (nready.nready == 0)
Pthread_cond_wait(&nready.cond, &nready.mutex);
nready.nready--;
Pthread_mutex_unlock(&nready.mutex);
if (buff[i] != i)
printf("buff[%d] = *d\n", i, buff[i]);
}
return(NULL);
}


50-58 - put.mutex.


59-64 nready.nready, , .
, , , pthread_cond_signal,
( ), . ,
. ,
(nready.mutex).
.

97

, nready.nready

72-76 , nready. nready .
, .
, pthread_cond_wait . :
1. nready.mutex.
2. , - pthread_cond_signal .
pthread_cond_wait nready.mutex. ,
, , (, )
. , pthread_cond_wait ,
. ,
.
, , :

struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
,
} var = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, };
Pthread_mutex_lock(&var.mutex);

Pthread_cond_signal(&var.cond);
Pthread_mutex_unlock(&var.mutex);
, , ,
. , 0 1.
, , , :

Pthread_mutex_lock(&var.mutex);
while ( )
Pthread_cond_wait(&var.cond, &var.mutex);

Pthread_mutex_unlock(&var.mutex);

, 7.6, pthread_cond_signal , ,
, . ,
, , ,
. , , 7.6 :

int dosignal;
Pthread_mutex_lock(nready.mutex);
dosignal = (nready.nready == 0);
nready.nready++;
Pthread_mutex_unlock(&nready.mutex);
if (dosignal)
Pthread_cond_signal(&nready.cond);
. Posix: ,
pthread_cond_signal, . Posix ,
, ,
pthread_cond_signal.
7.6. :
pthread_cond_signal , .
, . pthread_cond_broadcast
, .

, , 8,
. ,
, .
( ) ,
. , ,
, , .
.

#include
int pthread_cond_broadcast(pthread_cond_t *cptr);
int pthread_cond_timedwait(pthread_cond_t *cptr, pthread_mutex_t *mptr, const
struct timespec *abstime);
/* 0 ,
*/
pthread_cond_timedwait . abstime
timespec:

98

struct timespec {
time_t tv_sec; /* */
long tv_nsec; /* */
};
, ,
. ETIMEDOUT.
, . abstime
1 1970 UTC , . select, pselect poll
( 6 [24]), , . ( select
, pselect , a poll .) ,
(, ), ,
timespec.
7.7.
,
. : PTHREAD_MUTEX_INITIALIZER
PTHREAD_COND_INTIALIZER. ,
.

#include
int pthread_mutex_imt(pthread_mutex_t *mptr, const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mptr);
int pthread_cond_init(pthread_cond_t *ctr, const pthread_condattr_t *attr);
int pthread_cond_destroy(pthread_cond_t *cptr);
/* 0 ,
*/
, , . mptr pthread_mutex_t,
, pthread_mutex_init . pthread_mutexattr_t,
pthread_mutex_init(attr ), . ,
.
pthread_mutexattr_t, pthread_condattr_t,
:

#include
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
int pthread_condattr_init(pthread_condattr_t *attr);
int pthread_condattr_destroy(pthread_condattr_t *attr);
/* 0 ,
*/

. , (
). .
:

#include
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *valptr);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int value);
int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *valptr);
int pthread_condattr_setpshared(pthread_condattr_t *attr, int value);
/* 0 ,
*/
get , valptr, set
value. value PTHREAD_PROCESS_PRIVATE, PTHREAD_PROCESS_SHARED.
.

, _POSIX_THREAD_PROCESS_SHARED .
Posix.1 Unix 98 (. 1.3).
, ,
:

pthread_mutex_t *mptr; /* ,
*/
pthread_mutexattr_t mattr; /* */

mptr = /* , */
Pthread_mutexattr_init(&mattr);
#ifdef _POSIX_THREAD_PROCESS_SHARED
Pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
#else
# error _POSIX_THREAD_PROCESS_SHARED
#endif
Pthread_mutex_init(mptr, &mattr);

99

mattr pthread_mutexattr_t, ,
PTHREAD_PROCESS_SHARED, . pthread_mutex_init
. , ,
sizeof(pthread_mutex_t).
( mutex cond) PTHREAD_PROCESS_SHARED
, .
5.18.
,
, ,
(, ) .
. , -, Posix. ,
, fcntl ( 9). System V
, ( SEM_UNDO,
11.3).
, (cancel)
pthread_exit. , ,
, pthread_exit. ,
, 8.5. ,
. , , SIGSEGV,
, , ,
.
, .
, , , - . , ?
, , , , .
, , , , .
( ) . ,
System V ( SEM_UNDO) .
fork , .
, . , (
, ) , 9.7.
. - , ,
. . ,
, .
7.8.
(mutual exclusion mutex) ,
. , , -
. .
- . pthread_cond_wait, ,
. , (pthread_cond_signal),
(pthread_cond_broadcast).
. .
, . ,
, ,
.

1. 7.2 , ,
.
2. 7.1, Pthread_join -?
3. poay, pthread_mutexatt_init pthread_condattr_init .
- , ps. ? pthread_mutexattr_destroy pthread_condattr_destroy
, .
4. 7.6 pthread_cond_signal nready.nready 0 1.
, pthread_cond_signal , nready.nready 1,
.
8
-
8.1.
.
, .
.
-, .
:
1. , .
2. - , .
, , .
, .
, , ,
- .
,
.
- (shared-exclusive),
(shared lock),
(exclusive lock). ( ):
(readers and writers problem), (readers-writer lock).
, , .

, -, .
, - , ,
, .
.
, , Unix 98, - Posix.1 1996
. Unix, Aspen Group, 1995 ,
Posix.1. Posix (1003.1j) Pthreads,
-, , , .

100

8.2. -
- pthread_rwlock_t. ,
PTHREAD_RWLOCK_INITIALIZER.
pthread_rwlock_rdlock , , . pthread_rwlock_wrlock ,
, - - ( ).
pthread_rwlock_unlock ( ):
#include

int pthread_rwlock_rdlock(pthread_rwlock_t *rwptr);


int pthread_rwlock_wrlock(pthread_rwlock_t *rwptr);
int pthread_rwlock_unlock(pthread_rwlock_t *rwptr );
/* 0 ,
*/
, ,
EBUSY, :

#include
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwptr);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwptr);
/* 0 ,
*/
8.3. -
, PTHREAD_RWLOCK_INITIALIZER.
pthread_rwlock_init.
, pthread_rwlock_ destroy:

#include
int
pthread_rwlock_init(pthread_rwlock_t
*rwptr,
const
pthread_rwlockattr_t
*attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwptr);
/* 0 ,
*/
- attr , .
:

#include
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);
/* 0 ,
*/
pthread_rwlockattr_t .
PTHREAD_PROCESS_SHARED, ,
, .
:

#include
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *valptr);
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int value );
/* 0 ,
*/
, valptr.
value, PTHREAD_PROCESS_PRIVATE, PTHREAD_ PROCESS_SHARED.
8.4.
- .
, . ; .

, .
. 7.1.2 [3] ,
( ).
.18.2.3.1 IEEE 1996 [8] ,
. 14 [12] , .
, , (http://www.cs.wustl.edu/~schmidt/ACE.html), (Doug
Schmidt). Adaptive Communications Environment.
.
pthread_rwl ock_t
8.1[1] pthread_rwlock .h, pthread_rwlock_t ,
. .

8.1.
pthread_rwlock_t
//my_rwlock/pthread_rwlock.h
1 #ifndef __pthread_rwlock_h

101

#define __pthread_rwlock_h

3 typedef struct {
4
pthread_mutex_t rw_mutex; /* */
5
pthread_cond_t rw_condreaders; /* */
6
pthread_cond_t rw_condwriters; /* */
7
int rw_magic; /* */
8
int rw_nwaitreaders;/* */
9
int rw_nwaitwriters;/* */
10 int rw_refcount;
11 /* 1, , */
12 } pthread_rwlock_t;
13 #define RW_MAGIC 0x19283746
14 /* , */
15 #define PTHREAD_RWLOCK_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, \
16 PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, \
17 RW_MAGIC, 0, 0, 0 }
18 typedef int pthread_rwlockattr_t; /* */
19
20
21
22
23
24
25
26

/* */
int pthread_rwlock_destroy(pthread_rwlock_t *);
int pthread_rwlock_init(pthread_rwlock_t *, pthread_rwlockattr_t *);
int pthread_rwlock_rdlock(pthread_rwlock_t *);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *);
int pthread_rwlock_trywrlock(pthread_rwlock_t *);
int pthread_rwlock_unlock(pthread_rwlock_t *);
int pthread_rwlock_wrlock(pthread_rwlock_t *);

27
28
29
30
31
32
33
34

/* - */
void pthread_rwlock_destroy(pthread_rwlock_t *);
void pthread_rwlock_init(pthread_rwlock_t*, pthread_rwlockattr_t *);
void Pthread_rwlock_rdlock(pthread_rwlock_t *);
int Pthread_rwlock_tryrdlock(pthread_rwlock_t *);
int pthread_rwlock_trywrlock(pthread_rwlock_t *);
void pthread_rwlock_unlock(pthread_rwlock_t *);
void pthread_rwlock_wrlock(pthread_rwlock_t *);

35 #endif __pthread_rwlock_h
3-13 pthread_rwlock_t , , . ,
, .
rw_mutex. rw_magic RW_MAGIC.
, .
0 .
, rw_refcount -: 1 (
), 0 , ,
.
14-17 .
pthread_rwl ock_init
, pthread_rwlock_init, -. 8.2.
7-8 , , attr .
9-19 , .
0, rw_magi , , .
20-25 ,
.

8.2. pthread_rwlock_init:
-
102

//my_rwlock/pthread_rwlock_init.
1 #include "unpipc.h"
2 #include "pthread_rwlock.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

int
pthread_rwlock_init(pthread_rwlock_t *rw, pthread_rwlockattr_t *attr)
{
int result;
if (attr != NULL)
return(EINVAL); /* not supported */
if ((result = pthread_mutex_init(&rw->rw_mutex, NULL)) != 0)
goto err1;
if ((result = pthread_cond_init(&rw->rw_condreaders, NULL)) != 0)
goto err2;
if ((result = pthread_cond_init(&rw->rw_condwriters, NULL)) != 0)
goto err3;
rw->rw_nwaitreaders = 0;
rw->rw_nwaitwriters = 0;
rw->rw_refcount = 0;
rw->rw_magic = RW_MAGIC;
return(0);
err3:
pthread_cond_destroy(&rw->rw_condreaders);
err2;
pthread_mutex_destroy(&rw->rw_mutex);
err1:
return(result); /* errno */
}

pthread_rwl ock destroy


8.3 pthread_rwlock_destroy, .
8-13 , ,
.

8.. pthread_rwlock_destroy:
-
//my_rwlock/pthread_rwlock_destroy.
1 #include "unpipc.h"
2 #include "pthread_rwlock.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16

int
pthread_rwlock_destroy(pthread_rwlock_t *rw)
{
if (rw->rw_magic != RW_MAGIC)
return(EINVAL);
if (rw->rw_refcount != 0 ||
rw->rw_nwaitreaders != 0 || rw->rw_nwaitwriters != 0)
return(EBUSY);
pthread_mutex_destroy(&rw->rw_mutex);
pthread_cond_destroy(&rw->rw_condreaders);
pthread_cond_destroy(&rw->rw_condwriters);
rw->rw_magic = 0;
return(0);
}

pthread_rwlock_rdlock
pthread_rwlock_rdlock 8.4.

103

8.4. pthread_rwlock_rdlock:

//my_rwlock/pthread_rwlock_rdlock.
1 #include "unpipc.h"
2 #include "pthread_rwlock.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int
pthread_rwlock_rdlock(pthread_rwlock_t *rw)
{
int result;
if (rw->rw_magic != RW_MAGIC)
return(EINVAL);
if ((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
return(result);
/* */
while (rw->rw_refcount < 0 || rw->rw_nwaitwriters > 0) {
rw->rw_nwaitreaders++;
result = pthread_cond_wait(&rw->rw_condreaders, &rw->rw_mutex);
rw->rw_nwaitreaders--;
if (result != 0)
break;
}
if (result == 0)
rw->rw_refcount++; /* - */
pthread_mutex_unlock(&rw->rw_mutex);
return (result);
}

9-10 pthread_rwl ock_t rw_mutex, .


11-18 , rw_refcount ( )
, (rw_nwaitwriters 0). ,
rw_nwaitreaders pthread_cond_wait rw_condreaders. ,
, , ,
. , rw_condreaders .
19-20 rw_refcount. .

: pthread_cond_wait ,
, , rw_nwaitreaders .
pthread_rwlock_wrlock 8.6. 8.5.
pthread_rwl ock_tryrdlock
8.5 pthread_rwlock_tryrdlock, .

8.5. pthread_rwlock_tryrdlock:

//my_rwlock/pthread_rwlock_tryrdlock.
1 #include "unpipc.h"
2 #include "pthread_rwlock.h"
3 int
4 pthread_rwlock_tryrdlock(pthread_rwlock_t *rw)
5 {
6
int result;
7
if (rw->rwjnagic != RW_MAGIC)
8
return(EINVAL);
9
if ((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
10
return(result);
11 if (rw->rw_refcount < 0 || rw->rw_nwaitwriters > 0)

104

12
result = EBUSY; /*
, */
13 else
14
rw->rw_refcount++; /* */
15 pthread_mutex_unlock(&rw->rw_mutex);
16 return(result);
17 }
11-14 , ,
EBUSY. , rw_refcount.
pthread_rwl ock_wrl ock
pthread_rwlock_wrlock 8.6.
11-17 ( rw_refcount 0), .
rw_nwaitwriters pthread_cond_wait rw_condwriters.
-, .
18-19 rw_refcount 1.

8.6. pthread_rwlock_wrlock:

//my_rwlock/pthread_rwlock_wrlock.c
1 #include "unpipc.h"
2 #include "pthread_rwlock.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

int
pthread_rwlock_wrlock(pthread_rwlock_t *rw)
{
int result;
if (rw->rw_magic != RW_MAGIC)
return(EINVAL);
if ((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
return(result);
while (rw->rw_refcount != 0) {
rw->rw_nwaitwriters++;
result = pthread_cond_wait(&rw->rw_condwriters, &rw->rw_mutex);
rw->rw_nwaitwriters--;
if (result != 0)
break;
}
if (result == 0)
rw->rw_refcount = 1;
pthread_mutex_unlock(&rw->rw_mutex);
return(result);
}

pthread_rwlock_trywrl ock
pthread_rwlock_trywrlock 8.7.
11-14 rw_refcount ,
( ) EBUSY. ,
rw_refcount 1.

8.7. pthread_rwlock_trywrlock:

//my_rwlock/pthread_rwlock_trywrlock.c
1 #include "unpipc.h"
2 #include "pthread_rwlock.h"
3
4
5

int
pthread_rwlock_trywrlock(pthread_rwlock_t *rw)
{

105

6
int result;
7
if (rw->rw_magic != RW_MAGIC)
8
return(EINVAL);
9
if ((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
10
return(result);
11 if (rw->rw_refcount != 0)
12
result = EBUSY; /*
*/
13 else
14
rw->rw_refcount = 1; /* */
15 pthread_mutex_unlock(&rw->rw_mutex);
16 return(result);
17 }
pthread_rwlock_unl ock
, pthread_rwlock_unlock, 8.8.

8.8. pthread_rwlock_unlock:

//my_rwlock/pthread_rwlock_unlock.c
1 #include "unpipc.h"
2 #include "pthread_rwlock.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

int
pthread_rwlock_unlock(pthread_rwlock_t *rw)
{
int result;
if (rw->rw_magic != RW_MAGIC)
return(EINVAL);
if ((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
return(result);
if (rw->rw_refcount > 0)
rw->rw_refcount--; /* */
else if (rw->rw_refcount == 1)
rw->rw_refcount = 0; /* */
else
err_dump("rw_refcount = %d", rw->rw_refcount);
/* */
if (rw->rw_nwaitwriters > 0) {
if (rw->rw_refcount == 0)
result = pthread_cond_signal(&rw->rw_condwriters);
} else if (rw->rw_nwaitreaders > 0)
result = pthread_cond_broadcast(&rw->rw_condreaders);
pthread_mutex_unlock(&rw->rw_mutex);
return(result);
}

11-16 rw_refcount 0, . rw_refcount 1,


.
17-22 , rw_condwriters ( ,
rw_refcount 0). , ,
pthread_cond_signal. , , , ,
pthread_cond_broadcast rw_condreaders, . ,
, , .
, , .
if :

/* */
if (rw->rw_nwaitreaders > 0 && rw->rw_refcount == 0)
result = pthread_cond_signal(&rw->rw_condwriters);
else if (rw->rw_nwaitreaders > 0)
result = pthread_cond_broadcast(&rw->rw_condreaders);

106

rw->rw_refcount, pthread_cond_signal ,
.
8.5.
8.4, , ,
pthread_cond_wait. , - pthread_cancel,
, :

#include
int pthread_cancel(pthread_t tid);
/* 0 ,
*/
, - (,
) . .
, .
(push) (pop) - (cleanup handler):

#include
void pthread_cleanup_push(void (*function) (void *) void *arg);
void pthread_cleanup_pop(int execute);
, :
( , pthread_ cancel);
( pthread_exit ).
- ,
, .
function , arg . pthread_cleanup_pop
, execute 0.

15.26,
.

. . 8.1
, 8.9.

. 8.1. 8.9


10-13 , thread1, thread2.
, .


14-23 , PTHREAD_CANCEL.
, .
pthread_rwlock_t .

107

8.9. ,

//my_rwlock_cancel/testcancel.
1 #include "unpipc.h"
2 #include "pthread_rwlock.h"
3
4
5

pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;


pthread_t tid1, tid2;
void *thread1(void *), *thread2(void *);

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

int
main(int argc, char **argv)
{
void *status;
Set_concurrency(2);
Pthread_create(&tid1, NULL, thread1, NULL);
sleep(1); /* */
Pthread_create(&tid2, NULL, thread2, NULL);
Pthread_join(tid2, &status);
if (status != PTHREAD_CANCELED)
printf("thread2 status = %p\n", status);
Pthread_join(tid1, &status);
if (status != NULL)
printf("thread1 status = %p\n", status);
printf("rw_refcount = %d, rw_nwaitreaders = %d, rw_nwaitwriters = %d\n",
rwlock.rw_refcount, rwlock.rw_nwaitreaders,
rwlock.rw_nwaitwriters);
Pthread_rwlock_destroy(&rwlock);
exit(0);
}

26 void *
27 thread1(void *arg)
28 {
29 Pthread_rwlock_rdlock(&rwlock);
30 printf("thread1() got a read lock\n");
31 sleep(3); /*
pthread_rwlock_wrlock() */
32 pthread_cancel(tid2);
33 sleep(3);
34 Pthread_rwlock_unlock(&rwlock);
35 return(NULL);
36 }
37
38
39
40
41
42
43
44
45
46

void *
thread2(void *arg)
{
printf("thread2() trying to obtain a write lock\n"):
Pthread_rwlock_wrlock(&rwlock);
printf("thread2() got a write lock\n"); /* */
sleep(1);
Pthread_rwlock_unlock(&rwlock);
return(NULL);
}

108

thread1
26-36 3 . pthread_rwlock_wrlock
pthread_cond_wait, - .
pthread_cancel , 3 , .

thread2
37-46 ( ,
). .
:

solaris % testcancel
thread1() got a read lock
thread2() trying to obtain a write lock
. . :
1. pthread_rwlock_wrlock ( 8.6), pthread_cond_wait.
2. sl(3) pthread_cancel.
3. . , ,
-. ( ,
.) , rw_nwaitwriters
8.6 .
4. pthread_rwlock_unlock pthread_mutex_lock ( 8.8),
.
pthread_rwlock_unlock thread1, main :

rw_refcount = 1, rw_nwaitreaders = 0, rw_nwaitwriters = 1


pthread_rwlock_destroy error: Device busy
1, pthread_rwlock_ unlock, 1,
, .
. pthread_rwlock_rdlock 8.4. +:

rw->rw_nwaitreaders++;
+ pthread_cleanup_push(rwlock_cancelrdwait, (void *) rw);
result = pthread_cond_wait(&rw->rw_condreaders, &rw->rw_mutex);
+ pthread_cleanup_pop(0);
rw->rw_nwaitreaders++;
- ( rwlock_cancelrdwait), rw.
pthread_cond_wait . pthread_cleanup_pop , . , , .
pthread_cond_wait, . (
, 3 ).
8.10 rwlock_cancelrdwait, - phtread_rwlock_rdlock.

8.10. rwlock_cancelrdwait:

//my_rwlock_cancel/pthread_rwlock_rdlock.
3 static void
4 rwlock_cancelrdwait(void *arg)
5 {
6
pthread_rwlock_t *rw;
7
rw = arg;
8
rw->rw_nwaitreaders--;
9
pthread_mutex_unlock(&rw->rw_mutex);
10 }
8-9 rw_nwaitreaders , . ,
.
pthread_rwlock_wrlock 8.6.
pthread_cond_wait:

rw->rw_nwaitreaders++;
+ pthread_cleanup_push(rwlock_cancelrwrwait, (void*) rw);
result = pthread_cond_wait(&rw->rw_condwriters, &rw->rw_mutex);
+ pthread_cleanup_pop(0);
rw->rw_nwaitreaders--;
8.11 rwlock_cancelwrwait, - .

109

8.11. rwlock_cancelwrwait:

//my_rwlock_cancel/pthread_rwlock_wrlock.
3 static void
4 rwlock_cancelwrwait(void *arg)
5 {
6
pthread_rwlock_t *rw;
7
rw = arg;
8
rw->rw_nwaitwriters;
9
pthread_mutex_unlock(&rw->rw_mutex);
10 }
8-9 rw_nwaitwriters , . 8.9
:

solaris %testcancel
thread1() got a read lock
thread2() trying to obtain a write lock
rw_refcount = 0, rw_nwaitreaders = 0, rw_nwaitwriters = 0
, pthread_rwlock_unlock, pthread_rwlock_destroy
EBUSY.

, .
, , 5.3 [3].
8.6.
- , ,
, . Unix 98, .
Posix.
( 7).
- .
. , .
, , pthread_cond_wait,
, . -.

1. 8.4 , , .
2. 8.4 .
9

9.1.
-, , pthread_rwlock_t.
( ) ,
PTHREAD_PROCESS_SHARED,
-,
. ,
fcntl. , .
, fcntl , .
. ,
, , Unix ( lpr BSD lp System V). ,
, . ,
, ,
, . ,
. , , ,
. ASCII. ,
, :
1. .
2. .
3. .
, , .
, .

. 7
- 8. , ,
. ( ),
, fcntl.
, , -.
Unix 80-, .
, , ,
. 9.2 , . my_lock my_unlock
. .
20 (argv[0]) , main
,
.

pid_t long %ld.


, , , ,

110

long. , int %d, a pid_t


long, .
, , . 9.1 [1] my_lock my_unlock,
.

9.1. ,

//lock/locknone.c
1 void
2 my_lock(int fd)
3 {
4
return;
5 }
6
7
8
9
10

void
my_unlock(int fd)
{
return;
}

9.2. main

//lock/lockmain.c
1 #include "unpipc.h"
2 #define SEQFILE "seqno" /* */
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

void my_lock(int), my_unlock(int);


int
main(int argc, char **argv)
{
int fd;
long i, seqno;
pid_t pid;
ssize_t n;
char line[MAXLINE + 1];
pid = getpid();
fd = Open(SEQFILE, O_RDWR, FILE_MODE);
for (i = 0; i < 20; i++) {
my_lock(fd); /* */
Lseek(fd, 0L, SEEK_SET); /* */
n = Read(fd, line, MAXLINE);
line[n] = '\0'; /* 0 sscanf */
n = sscanf(line, "%ld\n", &seqno);
printf(%s; pid = %ld, seq# = %ld\n", argv[0], (long) pid, seqno);
seqno++; /* */
snprintf(line, sizeof(line), "%ld\n", seqno);
Lseek(fd, 0L, SEEK_SET); /* */
Write(fd, line, strlen(line));
my_unlock(fd); /* */
}
exit(0);
}

1 , :

solaris % locknone
locknone: pid = 15491, seq# = 1

111

locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:

pid
pid
pid
pid
pid
pid
pid
pid
pid
pid
pid
pid
pid
pid
pid
pid
pid
pid
pid

=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=

15491,
15491,
15491,
15491.
15491,
15491,
15491,
15491,
15491,
15491,
15491,
15491,
15491,
15491,
15491,
15491,
15491,
15491,
15491,

seq#
seq#
seq#
seq#
seq#
seq#
seq#
seq#
seq#
seq#
seq#
seq#
seq#
seq#
seq#
seq#
seq#
seq#
seq#

=
=
=
=
=
=

=
=
=
=
=
=
=
=
=
=
=
=

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

, main lockmain.c, ,
( 9.1), locknone. my_lock
my_unlock, - .
.
:

solaris %
solaris %
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:
locknone:

locknone & locknone&


locknone: pid = 15498, seq# = 1
pid = 15498, seq# = 2
pid = 15498, seq# = 3
pid = 15498, seq# = 4
pid = 15498, seq# = 5
pid = 15498, seq# = 6
pid = 15498, seq# = 7
pid = 15498, seq# = 8
pid = 15498, seq# = 9
pid = 15498, seq# = 10
pid = 15498, seq# = 11
pid = 15498, seq# = 12
pid = 15498, seq# = 13
pid = 15498, seq# = 14
pid = 15498, seq# = 15
pid = 15498, seq# = 16
pid = 15498, seq# = 17
pid = 15498, seq# = 18
pid = 15498, seq# = 19
pid = 15498, seq# = 20
pid = 15499, seq# = 1
pid = 15499, seq# = 2
pid = 15499, seq# = 3
pid = 15499, seq# = 4
pid = 15499, seq# = 5
pid = 15499, seq# = 6
pid = 15499, seq# = 7
pid = 15499, seq# = 8
pid = 15499, seq# = 9
pid 15499, seq# = 10
pid = 15499, seq# = 11
pid = 15499, seq# 12
pid = 15499, seq# = 13
pid = 15499, seq# = 14

112

locknone:
locknone:
locknone:
locknone:
locknone:
locknone:

pid
pid
pid
pid
pid
pid

=
=
=
=
=
=

15499,
15499,
15499,
15499,
15499,
15499,

seq#
seq#
seq#
seq#
seq#
seq#

=
=
=
=
=
=

15
16
17
18
19
20

, , , , .
.
. ( 15 498).
, ( 15499): 1. , , :
, (1), ,
. ,
(1). , . , 20 ( 40 ),
40.
- .
. my_lock my_unlock
( 7).
. ,
. , ;
40. 40,
. , , 1 20 21 40
. , .
.
9.2.
Unix , , .
.
. .
Posix 0 ( ) 0 ,
. , .
(granularity) . Posix
1 . . , ,
, . ,
(1 ).
( ), ,
. , .
3 (, , ). (
), , .
.

BSD flock.
.

. UUCP
( 9.8). ,
80-.
Version 7, John Bass) 1980
locking. (mandatory locking); System III Xenix. (
.)
4.2BSD ( ) flock 1983. 1984 /usr/group (
/Open) lockf, ( ), .
1984 System V Release 2 fcntl. lockf
, fcntl. ( lockf fcntl.) 1986 System V
Release 3 fcntl. set-group-ID ( )
9.5.
1988 Posix.1 fcntl,
, . X/Open Portability Guide Issue 3 (XPG3, 1988)
fcntl.
9.3. fcntl Posix
Posix, fcntl:

#include
int fcntl(int fd, int cmd, /* struct flock *arg */);
/* 1 : ,
, cmd */

cmd. , , arg,
flock:

struct
short
short
off_t
off_t
pid_t
};

flock {
l_type;
l_whence;
l_start;
l_len;
l_pid;

/*
/*
/*
/*
/*

F_RDLCK, F_WRLCK, F_UNLCK */


SEEK_SET, SEEK_CUR, SEEK_END */
*/
; 0 */
PID, F_GETLK */

( cmd ):
F_SETLK (l_type F_RDLCK, F_WRLCK) (l_type F_UNLCK),
flock, arg. ,
EACCESS EAGAIN.

113

F_SETLKW . ,
(W wait).
F_GETLK , arg. , l_type
flock, arg, F_UNLCK. flock, arg,
, , .
, F_GETLK F_SETLK . F_GETLK
F_UNLCK l_type, , F_SETLK .
.
, F_GETLK, , F_SETLK
. , ( ). ,
F_GETLK F_UNLCK, .
flock ( ) . 1 seek,
, , l_whence (SEEK_SET, SEEK_CUR,
SEEK_END).
l_len . 0 l_start . , ,
:
1. l_whence = SEEK_SET, l_start = 0 l_len = 0.
2. lseek, l_whence = SEEK_CUR, l_start = 0 l_len = 0.
, (fcntl . 9.10).
, , .
, , . ,
- . , ,
, .
, , .
fork.

fcntl ( )
System V. ( , , - Posix)
. 7.7.
-,
. read write, .

9.2 my_lock my_unlock 9.1 ,


Posix. 9.3.

9.3. fcntl
Posix
//lock/lockfcntl.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11

void
my_lock(int fd)
{
struct flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; /* */
Fcntl(fd, F_SETLKW, &lock);
}

12
13
14
15
16
17
18
19
20
21

void
my_unlock(int fd)
{
struct flock lock;
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; /* */
Fcntl(fd. F_SETLK, &lock);
}

, , (.
9.4). F_SETLKW, .

flock, , my_lock

static struct flock lock = { F_WRLCK, SEEK_SET, 0, 0, 0 };

. Posix , .

114

poa, , , .
, . , , - .
. , , ,
. , main ,
10000 , 20 . 1,
, 200001.
:
9.3 . ,
fcntl. , , 12.3 [21]:

#define read_lock(fd, offset, whence, len) \


lock_reg(fd, F_SETLK, F_RDLCK, offset, whence, len)
#define readw_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLKW, F_RDlCK, offset, whence, len)
#define write_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLK, F_WRLCK, offset, whence, len)
#define writew_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLKW, F_WRLCK, offset, whence, len)
#define un_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLK, F_UNLCK, offset, whence, len)
#define is_read_lockable(fd, offset, whence, len) \
lock_test(fd, F_RDLCK, offset, whence, len)
#define is_write_lockable(fd, offset, whence, len) \
lock_test(fd, F_WRLCK, offset, whence, len)
lock_reg lock_test, 9.4 9.5.
. lseek.
-, Lock_reg Lock_test, fcntl,
, , .
my_lock my_unlock 9.3

#define my_lock(fd) (Writew_lock(fd, 0, SEEK_SET, 0))


#define my_unlock(fd) (Un_lock(fd, 0, SEEK_SET, 0))

9.4. fcntl

//lib/lock_reg.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11

int
lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
{
struct flock lock;
lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */
lock.l_start = offset; /* l_whence */
lock.l_whence = whence; /* SEEK SET. SEEK CUR, SEEK END */
lock.l_len = len; /* (0 ) */
return(fcnt(fd, cmd, &lock)"); /* 1 */
}

9.5. fcntl

//lib/lock_test.c
1 #include "unpipc.h"
2
3
4
5
6

pid_t
lock_test(int fd, int type, off_t offset, int whence, off_t len)
{
struct flock lock;
lock.l_type = type; /* F_RDLCK or F_WRLCK */

115

*/

7
8
9

lock.l_start = offset; /* l_whence */


lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
lock.l_len = len; /* . 0

10 if (fcntl(fd, F_GETLK, &lock) == 1)


11 return(-1); /* */
12 if (lock.l_type == F_UNLCK)
13 return(0); /* false, */
14
return(lock.l_pid);
/*
true,

PID
*/
15 }

9.4.
Posix .
, . ,
. (advisory lock) (
).
(cooperating processes).
: . , , ,
.
:
, , (lockfcntl)
9.3 , (locknone)
9.1 :

solaris % lockfcntl & locknone &


lockfcntl: pid = 18816, seq# = 1
lockfcntl: pid = 18816, seq# = 2
lockfcntl: pid = 18816, seq# = 3
lockfcntl: pid = 18816, seq# = 4
lockfcntl: pid = 18816, seq# = 5
lockfcntl: pid = 18816, seq# = 6
lockfcntl: pid = 18816, seq# = 7
lockfcntl: pid = 18816, seq# = 8
lockfcntl: pid = 18816, seq# = 9
lockfcntl: pid = 18816, seq# = 10
lockfcntl: pid = 18816, seq# = 11
locknone: pid = 18817, seq# = 11
locknone: pid = 18817, seq# = 12
locknone: pid = 18817, seq# = 13
locknone: pid = 18817, seq# = 14
locknone: pid = 18817, seq# = 15
locknone: pid = 18817, seq# = 16
locknone: pid = 18817, seq# = 17
locknone: pid = 18817, seq# = 18
lockfcntl: pid = 18816, seq# = 12
lockfcntl: pid = 18816, seq# = 13
lockfcntl: pid = 18816, seq# = 14
lockfcntl: pid = 18816, seq# = 15
lockfcntl: pid = 18816, seq# = 16
lockfcntl: pid = 18816, seq# = 17
lockfcntl: pid = 18816, seq# = 18
lockfcntl: pid = 18816, seq# = 19
lockfcntl: pid = 18816, seq# = 20
locknone: pid = 18817, seq# = 19
locknone: pid = 18817, seq# = 20
locknone: pid = 18817, seq# = 21
locknone: pid = 18817, seq# = 22
locknone: pid = 18817, seq# = 23
locknone: pid = 18817, seq# = 24
locknone: pid = 18817, seq# = 25
locknone: pid = 18817, seq# = 26
locknone: pid = 18817, seq# = 27
locknone: pid = 18817, seq# = 28

116

locknone: pid = 18817, seq# = 29


locknone: pid = 18817, seq# = 30
lockfcntl , , 11 12 (
), poa locknone. 11
. , poao lockfcntl,
locknone.
9.5.
(mandatory locking).
read write, . O_NONBLOCK, read write,
, EAGAIN. O_NONBLOCK ,
, .

Posix.1 Unix 98 . , System V,


, . System V Release 3.
- :
group-execute ;
set-groupID .
, set-user ID user-execute ; set-group-ID group-execute.
, .
.
, , ls
l L, , . chmod
l, .

, ,
. ,
, , .
, seqno. ,
main, for ( 20)
printf :

solaris % cat > seqno



1
^D

solaris % ls l seqno
-rw-r--r-- 1 rstevens other1 2 Oct 7 11:24 seqno
solaris % chmod +l seqno
solaris % ls -l seqno
-rq-r-lr-- 1 rstevens other1 2 Oct 7 11:24 seqno
: loopfcntl fcntl, loopnone
.
10000 .

solaris % loopfcntl 10000 & loopnone 10000 &


solaris % wait

solaris % cat seqno

14378
, 20001

117

. 9.1. loopfcntl loopnone


14000 16000. ,
20001. , , aay , . 9.1.
, loopfcntl , .
, . loopnone,
read, , , . ,
13-15. , , ,
.
loopnone, 17-23. read write ,
15. , 5 23,
. 5. ( 7),
loopnone 36. 6. .
, ( 11), .
, ( ) ( 25-34) ,
( 23, 36 37). , ,
. .
9.6.
- 8.4 .
fcntl. ,
, . Posix .
:
, , : -
, ?
, ,
, , , .
, fcntl, ,
fork.
( ,
), . . 9.2,
9.6 .

118

. 9.2.

9.6.


//lock/test2.c
1 #include "unpipc.h"
2
3
4
5
6
7

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

int
main(int argc, char **argv)
{
int fd;
fd = Open("test1.data", O_RDWR | O_CREAT, FILE_MODE);
Read_lock(fd, 0, SEEK_SET, 0); /*
*/
printf("%s: parent has read lock\n", Gf_time());
if (Fork() == 0) {
/* */
sleep(1);
printf("%s: first child tries to obtain write lock\n", Gf_time());
Writew_lock(fd, 0, SEEK_SET, 0); /* */
printf("%s: first child obtains write lock\n", Gf_time());
sleep(2);
Un_lock(fd, 0, SEEK_SET, 0);
printf("ls: first child releases write lock\n", Gf_time());
exit(0);
}
if (Fork() == 0) {
/* */
sleep(3);

119

23
printf("%s: second child tries to obtain read lock\n", Gf_time());
24
Readw_lock(fd, 0, SEEK_SET, 0);
25
printf("%s: second child obtains read lock\n", Gf_time());
26
sleep(4);
27
Un_lock(fd, 0, SEEK_SET, 0);
28
printf("%s: second child releases read lock\n", Gf_time());
29
exit(0);
30 }
31 /* */
32 sleep(5);
33 Un_lock(fd, 0, SEEK_SET, 0);
34 printf("%s: parent releases read lock\n", Gf_time());
35 exit(0);
36 }



6-8 . ,
read_lock ( ), readw_lock ( ), ,
. gf_time [24, . 404], .


9-19 , 1 .
, 2 , .


20-30 , 3 , ,
. readw_lock ,
. .

5
31-35 , .
. 9.2 Solaris 2.6, Digital Unix 4.0B BSD/OS 3.1. ,
, . ,
, . ,
:

alpha % test2
16:32:29.674453: parent has read lock
16:32:30.709197: first child tries to obtain write lock
16:32:32.725810: second child tries to obtain read lock
16:32:32.728739: second child obtains read lock
16:32:34.722282: parent releases read lock
16:32:36.729738: second child releases read lock
16:32:36.735597: first child obtains write lock
16:32:38.736938: first child releases write lock
: ?
, , :
, ? .
9.7 , . 9.3 .

120

9.7.

//lock/test3.c
1 #include "unpipc.h"
2
3
4
5
6
7

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

int
main(int argc, char **argv)
{
int fd;
fd = Open("test1.data", O_RDWR | O_CREAT, FILE_MODE);
Write_lock(fd, 0, SEEK_SET, 0); /*
*/
printf("ls: parent has write lock\n", Gf_time());
if (Fork() == 0) {
/* */
sleep(1);
printf("ls: first child tries to obtain write lock\n", Gf_time());
Writew_lock(fd, 0, SEEK_SET, 0); /* */
printf("%s: first child obtains write lock\n", Gf_time());
sleep(2);
Un_lock(fd, 0, SEEK_LET, 0);
printf("ls: first child releases write lock\n", Gf_time());
exit(0);
}
if (Fork() == 0) {
/* */
sleep(3);
printf("ls: second child tries to obtain read lock\n", Gf_time());
Readw_lock(fd, 0, SEEK_SET, 0);
printf(%s: second child obtains read lock\n", Gf_time());
sleep(4);
Un_lock(fd, 0, SEEK_SET, 0);
printf("ls: second child releases read lock\n", Gf_time());
exit(0);
}
/* */
sleep(5);
Un_lock(fd, 0, SEEK_SET, 0);
printf("ls: parent releases write lock\n", Gf_time());
exit(0);
}



6-8 .


9-19 , , . ,
, , ,
.


121

20-30 , , .
.
Solaris 2.6, Digital Unix 4.0B , , . 9.3.
, , , ,
, . , ,
9.7, , .
, Solaris Digital Unix . BSD/OS 3.1
.

. 9.3.
9.7, aaa . 9.3:

alpha % test3
16:34:02.810285:
16:34:03.848166:
16:34:05.861082:
16:34:07.858393:
16:34:07.865222:
16:34:09.865987:
16:34:09.872823:
16:34:13.873822:

parent has write lock


first child tries to obtain write lock
second child tries to obtain read lock
parent releases write lock
first child obtains write lock
first child releases write lock
second child obtains read lock
second child releases read lock

9.7.
- poa (, ) .
, 9.8, .

9.8.

//lock/onedaemon.c
1 #include "unpipc.h"
2 #define PATH_PIDFILE "pidfile"
3

int

122

4 main(int argc, char **argv)


5 {
6
int pidfd;
7
char line[MAXLINE];
8
/* */
9
pidfd = Open(PATH_PIDFILE, O_RDWR | O_CREAT, FILE_MODE);
10 /* */
11 if (write_lock(pidfd, 0, SEEK_SET, 0) < 0) {
12
if (errno == EACCES || errno == EAGAIN)
13
err_quit("unable to lock %s, is %s already running?",
14
PATH_PIDFILE, argv[0]);
15
else
16
err_sys("unable to lock %s", PATH_PIDFILE):
17 }
18 /* : , */
19 snprintf(line, sizeof(line), "%ld\n", (long) getpid());
20 Ftruncate(pidfd, 0);
21 Write(pidfd, line, strlen(line));
22 /* */
23 pause();
24 }


8-17 , . ,
. , , ,
.

Unix . Solaris 2.6 /etc, a Digital Unix 4.0B


BSD/OS /var/run.


18-21 0 , . , ,
, , ,
.
9.8:

solaris %
[1] 22388
solaris %
22388
solaris %
unable to

onedaemon&

cat pidfile
onedaemon

lock pidfile, is onedaemon already running?

, . ,
,
.
9.8.
Posix.1 , open O_CREAT ( , ) O_EXCL
( ), , . , (
) . ,
. , ( ),
unlink.
9.9 , . open
, , my_lock. , .
, . open EEXIST,
, .
.
1. , , , , . ,
, .
, , .
, .
fcntl, .
2. - , open, .
. sleep 1 , open
( 7.4).
fcntl, F_SETLKW.
, .

123

3. open unlink , ,
fcntl ( : , ). fcntl
10000 75 , , open unlink.

9.9.
open O_CREAT O_EXCL
//lock/lockopen.c
1 #include "unpipc.h"
2 #define LOCKFILE "/tmp/seqno.lock"
3
4
5

void
my_lock(int fd)
{

6
int tempfd;
7
while ((tempfd = open(LOCKFILE, O_RDWR|O_CREAT|O_EXCL, FILE_MODE)) < 0) {
8
if (errno != EEXIST)
9
err_sys("open error for lock file");
10
/* - , */
11 }
12 Close(tempfd); /* , */
13 }
14
15
16
17
18

void
my_unlock(int fd)
{
Unlink(LOCKFILE); /* */
}

Unix, . , link
, . ,
( ,
). link - .
unlink. unlink.
link EEXIST, ( 9.9).
, , , Unix
( link) .
, open , O_TRUNC
. open, O_CREAT | O_WRONLY | O_TRUNC mode 0 (
0). , unlink
. open EACESS, ( 9.9).
, .
, , : fcntl. ,
, ,
fcntl.
9.9. NFS
NFS Network File System ( ); 29 [22].
fcntl NFS, .
: lockd statd. fcntl , NFS.
lockd lockd . statd ,
, lockd .
NFS , ,
. NFS ,
SEQFILE 9.2. , 10000
, 80 , . ,
( ).

NFS , .
, Unix - , fcntl NFS
. : fcntl NFS,
.
9.10.
fcntl ,
. , .
, .
, .
,
.
fcntl , ( ,
8 -). , (
8.4) , .

124


1. locknone 9.2 9.1 . , .
2. 9.2 , . ?
3. , putchar ( printf). ?
4. my_lock 9.3 , , . ?
5. open loopmain.c, O_NONBLOCK. loopfcntlnonb .
?
6. , loopmain. loopnonenonb ( locknone.c).
seqno. loopfcntlnonb
. ?
7. loopfcntl 10 . 10
10000. .
?
8. fork 9.6 9.7 , pthread_create
?
9. 9.9 ftruncate 0 . O_TRUNC ?
10. SEEK_SET, SEEK_CUR SEEK_END
?
10
Posix
10.1.
. :
Posix, , Posix IPC (. 2.2);
Posix;
System V ( 11), .
, .
, ,
0 1. . 10.1.

. 10.1.

, ( System V).
Posix . ,
. . 10.2 ,
Posix.

. 10.2. , Posix

. 10.2 : Posix ,
. , , ,
. (
10.15) ,
, .
. 10.1 10.2 , :
1. . ( 1, 0).
2. (wait). ,
0, 0 1.

while (semaphore_value <= 0); /* wait: .. */


semaphore_value--; /* */
while
( ) ( , System V
80- . ,
).

125

. , proben (, ),
. down ( ) lock,
Posix (wait).
3. (post). ,

semaphore_value++;
, , 0, .
, ,
.
. V, verhogen ().
up ( ), unlock signal. , Posix, post.
, , . , , , . ,
.
, . ,
. -.
N, (, ).
, -.

, .
.
( ). 10.1
.

10.1.

;
pthread_mutex_lock(&mutex);

pthread_mutex_unlock(&mutex);

;
sem_wait(&sem);

sem_post(&sem);

1. sem_wait, , 0, 1.
sem_post 0 1 , sem_wait .
, :
, , .
7
. . 10.3 , , ,
. , .

. 10.3.
10.2 .

10.2.

Producer
Consumer
get 0;
put 1;
for (;;) {
for (;;) {
sem_wait(&put);
sem_wait(&get);
;
;
sem_post(&get);
sem_post(&put);
}
}
put oaae , get
. poaa :
1. .
2. . sem_wait, get 0.
3. . sem_wait put 1 0,
. sem_post get 0 1. ,
, . , , .
sem_wait for, put 0. ,
.
4. sem_wait, get 0 1. sem_post,
put 0 1. -
. , . sem_wait for,
get 0.
5. sem_wait, , .

126

, sem_post ,
. ,
sem_post , ( ).
:
1. , ,
. .
2. , ( , ).
3. , ,
wait , .
10.2 , sem_wait.
, sem_post get ( 0 1), sem_wait
put. for sem_wait get, 1
0, .

Posix.1 (Rationale)
: ;
. ,
. .
. 10.15 , - 300 ,
.
, .
, .
, Posix : (named) (memory-based unnamed).
. 10.4 , .
Posix . 10.2. , , ,
, . 10.5.

. 10.4. Posix

. 10.5. ,

. 10.6 ( 4), .
.

. 10.6. ,
Posix, .
7.3 , ,
. , -
.
Posix: FIFO, System
V.
10.2. sem_open, sem_cl ose sem_ unlink
sem_open .
:

#include
sem_t *sem_open(const char *name, int oflag,
/* mode_t mode, unsigned int value */);

127

/* , SEM_FAILED
*/
2.2.
oflag 0, O_CREAT, O_CREAT | O_EXCL, 2.3. O_CREAT,
. mode (. 2.3), a value
. SEM_VALUE_MAX, , Posix, 32767.
1, - .
O_CREAT ( O_EXCL) , . ,
. , O_CREAT | O_EXCL.
sem_t.
sem_close, sem_wait, sem_trywait, sem_post sem_getvalue.

SEM_FAILED . Posix
1, SEM_FAILED

#define SEM_FAILED ((sem_t *)(-1))

Posix.1 , . , . 2.2
, O_RDONLY, O_WRONLY O_RDWR. ,
(Digital Unix 4.0B Solaris 2.6), ( ) , .
, , , , (post wait),
. sem_open EACCESS ("Permission denied").
sem_open, , sem_close:

#include
int sem_close(sem_t *sem);
/* 0 . 1 */
, .
( exit _exit), ( ).
. Posix .
, .
sem_unlink:

#include
int sem_unlink(const char *name);
/* 0 , 1 */
, ( ), sem_unlink
unlink : , - ,
, .
10.3. sem_wait sem_trywait
sem_wait ,
. , , ,
. ,
, :

#include
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
/* 0 . 1 */
sem_wait sem_trywait , ,
, EAGAIN.
sem_wait , . EINTR.
10.4. sem_post sem_ getvalue
sem_post. 10.1,
, :

#include
int sem_post(sem_t *sem);
int sem_getvalue(sem_t *sem, int *valp);
/* 0 . 1 */
sem_getvalue , , valp.
, 0, , , .
.
. :
, 1 0 ( ), 0 1,
.
, , post wait,
(, 0 1), , . pthread_cond_signal
pthread_cond_wait , .
, , , ,
- , : sem_post.

. ,
, , -, fcntl, .
.
, , , ,
.
10.5.
, Posix.
. Posix ,
.
semcreate

128

10.3 , . ,
( , ), i
, 1.

10.3. [1]
//pxsem/semcreate.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

int
main(int argc, char **argv)
{
int , flags;
sem_t *sem;
unsigned int value;
flags = O_RDWR | O_CREAT;
value = 1;
while ((c = Getopt(argc, argv, "ei:")) != 1) {
switch (c) {
case 'e':
flags |= O_EXCL;
break;
case 'i':
value = atoi(optarg);
break;
}
}
if (optind != argc 1)
err_quit("usage: semcreate [ e ] [ i initialvalue ] ");
sem = Sem_open(argv[optind], flags, FILE_MODE, value);
Sem_close(sem);
exit(0);
}


22 O_CREAT, sem_open .
, .


23 sem_close, , ,
.
semunl ink
10.4 .

10.4.
//pxsem/semunlink.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5 if (argc != 2)
6
err_quit("usage: semunlink ");
7 Sem_unlink(argv[1]);
8 exit(0);

129

9 }
semgetvalue
10.5 , ,
.

10.5.
//pxsem/semgetvalue.
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13

int
main(int argc, char **argv)
{
sem_t *sem;
int val;
if (argc != 2)
err_quit("usage: semgetvalue ");
sem = Sem_open(argv[1], 0);
Sem_getvalue(sem, &val);
printf("value = %d\n", val);
exit(0);
}


9 , , . sem_open 0:
O_CREAT 0_.
semwait
10.6 , semwait ( ,
0, 1), ,
pause.

10.6.

//pxsem/semwait.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15

int
main(int argc, char **argv)
{
sem_t *sem;
int val;
if (argc != 2)
err_quit("usage: semwait ");
sem = Sem_open(argv[1], 0);
Sem_wait(sem);
Sem_getvalue(sem, &val);
printf("pid %ld has semaphore, value = %d\n", (long) getpid(), val);
pause(); /* , */
exit(0);
}

sempost
10.7 , post ( 1),
.

10.7.
130

//pxsem/sempost.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14

int
main(int argc, char **argv)
{
sem_t *sem;
int val;
if (argc != 2)
err_quit("usage: sempost ");
sem = Sem_open(argv[1], 0);
Sem_post(sem);
Sem_getvalue(sem, &val);
printf("value = %d\n", val);
exit(0);
}

Digital Unix 4.0B , :

alpha % semcreate /tmp/test1


alpha % ls-l /tmp/test1
-rw-r--r-- 1 rstevens system 264 Nov 13 08:51 /tmp/test1
alpha %semgetvalue /tmp/test1
value = 1
Posix , .
, :

alpha % semwait /tmp/test1


pid 9702 has semaphore, value = 0 sem_wait
^?

alpha % semgetvalue /tmp/test1
value = 0

. -, . 1,
, , . -,
semwait, , , .
fcntl, 9, .
, ,
:

alpha % semgetvalue /tmp/test1


value = 0

alpha % semwait /tmp/test1 &



[1] 9718

alpha % semgetvalue /tmp/test1


value = 1

alpha % semwait /tmp/test1 &

[2] 9727

alpha % semgetvalue /tmp/test1
value = 2

alpha % sempost /tmp/test1
value = 1
sem_post
pid 9718 has semaphore, value = 1 semwait
alpha % sempost /tmp/test1
value = 0
pid 9727 has semaphore, value = 0 semwait
sem_post 2 1 , ,
.
Solaris 2.6, :

solaris % semcreate /test2


solaris % ls l /tmp/.*test2*
-rw-r--r-- 1 rstevens other1 48 Nov 13 09:11 /tmp/.SEMDtest2
rw-rw-rw 1 rstevens other1 0 Nov 13 09:11 /tmp/.SEMLtest2
solaris % semgetvalue /test2

131

value = 1
Posix /tmp, .
sem_open, , , .
, , :

solaris % semwait /test2


pid 4133 has semaphore, value = 0
^?
solaris % semgetvalue /test2
value = 0
, , :

solaris % semgetvalue /test2


value = 0

solaris % semwait /test2&

[1] 4257

solaris % semgetvalue /test2
value = 0

solaris % semwait /test2&



[2] 4263
solaris % semgetvalue /test2
value 0

solaris % sempost /test2


post
pid 4257 has semaphore, value = 0 semwait
value = 0
solaris % sempost /test2
pid 4263 has semaphore, value = 0 semwait
value = 0
Digital Unix 4.0B:
.
10.6.
7.3 , , -.
1. ( 7.2) ,
, .
2. ( 7.5) ,
( ) (
).
, : ,
(buff[NBUFF-1]) (buff[0]), .
: . ,
, ,
(, , 4).
:
1. , .
2. , .
3. (, , ..),
, , .
:
1. mutex : ( )
( ). , , . (,
. . 10.10.)
2. - nempty . ,
(NBUFF).
3. - nstored . ,
.

132

. 10.7. -

. 10.7 - .
.
0 NLOOP-1 (buff[0] = 0, buff[1] = 1), .
, .
. 10.8 - , .

. 10.8.
, . . 10.9.

. 10.9.

10.8 main, , , .

10.8. main

//pxsem/prodcons1.
1 #include "unpipc.h"
2 #define NBUFF 10
3 #define SEM_MUTEX "mutex" /* px_ipc_name() */
4 #define SEM_NEMPTY "nempty"
5 #define SEM_NSTORED "nstored"
6
7
8
9
10
11

int nitems; /* read-only */


struct { /* */
int buff[NBUFF];
sem_t *mutex, *nempty, *nstored;
} shared;
void *produce(void *), *consume(void *);

12 int
13 main(int argc, char **argv)
14 {

133

15 pthread_t tid_produce, tid_consume;


16 if (argc != 2)
17
err_quit("usage: prodcons1 <#items>");
18 nitems = atoi(argv[1]);
19 /* */
20 shared.mutex = Sem_open(Px_ipc_name(SEM_MUTEX), O_CREAT | O_EXCL,
21
FILE_MODE, 1);
22 shared.nempty = Sem_open(Px_ipc_name(SEM_NEMPTY), 0_CREAT | O_EXCL,
23
FILE_MODE, NBUFF);
24 shared.nstored = Sem_open(Px_ipc_name(SEM_NSTORED), O_CREAT | O_EXCL,
25
FILE_MODE, 0);
26 /* - - */
27 Set_concurrency(2);
28 Pthread_create(&tid_produce, NULL, produce, NULL);
29 Pthread_create(&tid_consume, NULL, consume, NULL);
30 /* */
31 Pthread_join(tid_produce, NULL);
32 Pthread_join(tid_consume, NULL);
33 /* */
34 Sem_unlink(Px_ipc_name(SEM_MUTEX));
35 Sem_unlink(Px_ipc_name(SEM_NEMPTY));
36 Sem_unlink(Px_ipc_name(SEM_NSTORED));
37 exit(0);
38 }


6-10 , NBUFF , . 7,
, , .


19-25 , px_ipc_name. O_EXCL ,
.
, , sem_unlink .
EEXIST sem_open O_EXCL, sem_unlink sem_open, .
, ( ), 9.7,
.


26-29 , , . .
30-36 , .

sem_close, .
.
10.9 produce consume.

10.9. produce consume


//pxsem/prodcons1.c
39 void *
40 produce(void *arg)
41 {
42 int i;
43 for (i = 0; i < nitems; i++) {
44
Sem_wait(shared.nempty); /* */
45
Sem_wait(shared.mutex);
46
shared.buff[i % NBUFF] = i; /* i */
47
Sem_post(shared.mutex);

134

48
Sem_post(shared.nstored); /* 1 */
49 }
50 return(NULL);
51 }
52
53
54
55
56
57
58
59
60
61
62
63
64
65

void *
consume(void *arg)
{
int i;
for (i = 0; i < nitems; i++) {
Sem_wait(shared.nstored); /* */
Sem_wait(shared.mutex);
if (shared.buff[i % NBUFF] != i)
printf("buff[%d] = %d\n", i, shared.buff[i % NBUFF]);
Sem_post(shared.mutex);
Sem_post(shared.nempty); /* */
}
return(NULL);
}

44 sem_wait nempty, .
nempty NBUFF NBUFF-1.


45-48 mutex. ,
i % NBUFF,
( , ). ,
mutex . ,
( , ).
mutex ( 0 1)
nstored. nstored 0 1.

nstored
57-62 nstored 0, .
, mutex.
nempty, .

, Sem_wait consumer ( 10.9)? ,


( , 10.1). NBUFF , nempty NBUFF
0 nstored 0 NBUFF. Sem_wait(shared. nempty),
.
NBUFF . nstored NBUFF 0
nempty 0 NBUFF. Sem_wait(shared, nstored) Sem_wait(shared, mutex).
, nempty 0, Sem_wait(shared, mutex)
.
(deadlock). mutex,
, nstored. nstored, mutex. ,
: , .

Posix sem_wait EDEADLK, ,


(Digital Unix 4.0B Solaris 2.6), .
10.7.
9. my_lock my_unlk,
Posix. 10.10 .

10.10.
Posix
135

//lock/lockpxsem.c
1 #include "unpipc.h"
2 #define LOCK_PATH "pxsemlock"
3 sem_t *locksem;
4 int initflag;
5
6
7
8
9
10
11
12
13

void
my_lock(int fd)
{
if (initflag == 0) {
locksem = Sem_open(Px_ipc_name(LOCK_PATH), O_CREAT, FILE_MODE, 1);
initflag = 1;
}
Sem_wait(locksem);
}

14
15
16
17
18

void
my_unlock(int fd)
{
Sem_post(locksem);
}

.
sem_wait, sem_post.
10.8. sem_init sem_ destroy
Posix. , ,
. Posix , ,
( sem_t), :

#include
int sem_init(sem_t *sem, int shared, unsigned int value);
/* 1 */
int sem_destroy(sem_t *sem);
/* 0 , 1 */
sem_init. sem sem_t,
. shared 0, ,
. shared ,
, . sem_open, value .
, sem_destroy.
1
sem_open , shared; , PTHREAD_PROCESS_SHARED (
7),
.
2
, O_CREAT: sem_init
. , , sem_init . ( 10.2
.) sem_init
.
3
, sem_open sem_init. sem_t,
. , sem_init
sem_t, . sem_init
.
4
Posix.1 , ,
sem_init. .
sem_init 1 , 0 . ,
Posix. 1 , , , 0 .
, ,
. .
.
. 1.1 , , , ,
. , ,
, - .
( shared sem_init 0),
.
( shared seminit 1),
, , . ,
Posix, System V (. 1.1). , ,
Posix, .
.
, , :

sem_t mysem;
Sem_init(&mysem, 1.0); /* 2- 1 > */

136

if (Fork() == 0) { /* */

Sem_post(&mysem);
}
Sem_wait(&mysem); /* : */
, (. 10.12). , ,
fork. , , .

10.8 10.9
Posix. 10.11 .

10.11.


//pxsem/prodcons2.c
1 #include "unpipc.h"
2 #define NBUFF 10
3
4
5
6
7
8

int nitems; /* */
struct { /* */
int buff[NBUFF];
sem_t mutex, nempty, nstored; /* , */
} shared;
void *produce(void *), *consume(void *);

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

int
main(int argc, char **argv)
{
pthread_t tid_produce, tid_consume;
if (argc != 2)
err_quit("usage: prodcons2 <#items>");
nitems = atoi(argv[1]);
/* */
Sem_init(&shared.mutex, 0, 1);
Sem_init(&shared.nempty, 0, NBUFF);
Sem_init(&shared.nstored, 0, 0);
Set_concurrency(2);
Pthread_create(&tid_produce, NULL, produce, NULL);
Pthread_create(&tid_consume, NULL, consume, NULL);
Pthread_join(tid_produce, NULL);
Pthread_join(tid_consume, NULL):
Sem_destroy(&shared.mutex);
Sem_destroy(&shared.nempty):
Sem_destroy(&shared.nstored);
exit(0);
}

30 void *
31 produce(void *arg)
32 {
33 int i;
34 for (i = 0; i < nitems; i++) {
35
Sem_wait(&shared.nempty); /* */
36
Sem_wait(&shared.mutex);
37
shared.buff[i % NBUFF] = i; /* i */
38
Sem_post(&shared.mutex);

137

39
Sem_post(&shared.nstored); /* */
40 }
41 return(NULL);
42 }
43 void *
44 consume(void *arg)
45 {
46 int i;
47 for (i = 0; i < nitems; i++) {
48
Sem_wait(&shared.nstored); /*
*/
49
Sem_wait(&shared.mutex);
50
if (shared.buff[i % NBUFF] != i)
51
printf("buff[*d] = *d\n", i, shared.buff[i % NBUFF]);
52
Sem_post(&shared.mutex);
53
Sem_post(&shared.nempty); /* */
54 }
55 return(NULL);
56 }


6 sem_t, , .

sem_init
16-27 sem_init sem_open* sem_destroy sem_unlink. sem_destroy ,
.
sem_wait sem_post.
10.9. ,
10.6 . ,
. 10.11,
. 10.12 main.

10.12. main

//pxsem/prodcons3.c
1 #include "unpipc.h"
2 #define NBUFF 10
3 #define MAXNTHREADS 100
4 int nitems, nproducers; /* */
5 struct { /* */
6
int buff[NBUFF];
7
int nput;
8
int nputval;
9
sem_t mutex, nempty, nstored; /* , */
10 } shared;
11 void *produce(void *), *consume(void *);
12 int
13 main(int argc, char **argv)
14 {
15 int i, count[MAXNTHREADS];

138

16 pthread_t tid_produce[MAXNTHREADS], tid_consume;


17 if (argc != 3)
18
err_quit("usage: prodcons3 <#items> <#producers>");
19 nitems = atoi(argv[1]);
20 nproducers = min(atoi(argv[2]), MAXNTHREADS);
21 /* */
22 Sem_init(&shared.mutex, 0, 1);
23 Sem_init(&shared.nempty, 0, NBUFF);
24 Sem_init(&shared.nstored, 0, 0);
25 /* */
26 Set_concurrency(nproducers + 1);
27 for (i = 0; i < nproducers; i++) {
28
count[i] = 0;
29
Pthread_create(&tid_produce[i], NULL, produce, &count[i]);
30 }
31 Pthread_create(&tid_consume, NULL, consume, NULL);
32 /* */
33 for (i = 0; i < nproducers; i++) {
34
Pthread_join(tid_produce[i], NULL);
35
printf("count[%d] = %d\n", i, count[i]);
36 }
37 Pthread_join(tid_consume, NULL);
38 Sem_destroy(&shared.mutex);
39 Sem_destroy(&shared.nempty);
40 Sem_destroy(&shared.nstored);
41 exit(0);
42 }


4 nitems , . nproducers
-. .


5-10 shared : nput, , (
BUFF), nputval , . 7.1 7.2.
-.


17-20 , ,
-.


21-41 - -. .
7.1.
10.13 produce, -.

10.13. ,
-
//pxsem/prodcons3.c
43 void *
44 produce(void *arg)
45 {

139

46 for (;;) {
47
Sem_wait(&shared.nempty); /* */
48
Sem_wait(&shared.mutex);
49
if (shared.nput >= nitems) {
50
Sem_post(&shared.nempty);
51
Sem_post(&shared.mutex);
52
return(NULL); /* */
53
}
54
shared.buff[shared.nput % NBUFF] = shared.nputval;
55
shared.nput++;
56
shared.nputval++;
57
Sem_post(&shared.mutex);
58
Sem_post(&shared.nstored); /* */
59
*((int *) arg) += 1;
60 }
61 }


49-53 10.8 , , nitems . ,
- nempty , mutex.
nput nval .


50-51 -. ,

Sem_wait(&shared.nempty); /* */
, nempty. , , ,
. mutex,
. nempty ,
, , nempty, .
consume 10.14 , .

10.14. ,
//pxsem/prodcons3.
62 void *
63 consume(void *arg)
64 {
65 int i;
66 for (i = 0; i < nitems; i++) {
67
Sem_wait(&shared.nstored); /*
*/
68
Sem_wait(&shared.mutex);
69
if (shared.buff[i % NBUFF] != i)
70
printf("error: buff[%d] = %d\n", i, shared.buff[i % NBUFF]);
71
Sem_post(&shared.mutex);
72
Sem_post(&shared.nempty); /* */
73 }
74 return(NULL);
75 }

- :
nitems.
10.10. ,
, poay,
. .
, .

140

1. poaa IP- . IP-, gethostbyaddr ( 9.6 [24]),


. gethostbyaddr , IP- ,
, , -.
gethostbyaddr ( ) -.

gethostbyaddr, , . ,
.
2. , UDP, . eaaa
-, . ,
, , .
10.15 .

10.15.
//pxsem/prodcons4.
1 #include "unpipc.h"
2 #define NBUFF 10
3 #define MAXNTHREADS 100
4 int nitems, nproducers, nconsumers; /* */
5 struct { /* */
6
int buff[NBUFF];
7
int nput; /* : 0, 1. 2, */
8
int nputval; /* buff[] */
9
int nget; /* : 0, 1, 2, */
10 int ngetval; /* buff[] */
11 sem_t mutex, nempty, nstored; /* , */
12 } shared;
13 void *produce(void *), *consume(void *);


4-12 - , . shared
: nget , -, ngetval .
main, 10.16, - - .
19-23 -. -
(tid_consume), conscount.
24-50 - , .

10.16. main

//pxsem/prodcons4.
14 int
15 main(int argc, char **argv)
16 {
17 int i, prodcount[MAXNTHREADS], conscount[MAXNTHREADS];
18 pthread_t tid_produce[MAXNTHREADS], tid_consume[MAXNTHREADS];
19 if (argc != 4)
20
err_quit("usage: prodcons4 <#items> <#producers> <#consumers>");
21 nitems = atoi(argv[1]);
22 nproducers = min(atoi(argv[2]), MAXNTHREADS);
23 nconsumers = min(atoi(argv[3]), MAXNTHREADS);
24 /* */
25 Sem_init(&shared.mutex, 0, 1);
26 Sem_init(&shared.nempty, 0, NBUFF);
27 Sem_init(&shared.nstored, 0, 0);
28 /* */
29 Set_concurrency(nproducers + nconsumers);
30 for (i = 0; i < nproducers; i++) {
31
prodcount[i] = 0;
32
Pthread_create(&tid_produce[i], NULL, produce, &prodcount[i]);

141

33 }
34 for (i = 0; i < nconsumers; i++) {
35
conscount[i] = 0;
36
Pthread_create(&tid_consume[i], NULL, consume, &conscount[i]);
37 }
38 /* */
39 for (i = 0; i < nproducers: i++) {
40
Pthread_join(tid_produce[i], NULL);
41
printf("producer count[%d] = %d\n", i, prodcount[i]);
42 }
43 for (i = 0; i < nconsumers; i++) {
44
Pthread_join(tid_consume[i], NULL);
45
printf("consumer count[%d] = %d\n", i, conscount[i]);
46 }
47 Sem_destroy(&shared.mutex);
48 Sem_destroy(&shared.nempty);
49 Sem_destroy(&shared.nstored);
50 exit(0);
51 }
produce 10.13. , -,
, +:

if (shared.nput >= nitems) {


+ Sem_post(&shared.nstored); /* */
Sem_post(&shared.nempty);
Sem_post(&shared.mutex);
return(NULL); /* */
}
- .

Sem_wait(&shared.nstored); /* */
nstored eee, , .
consume 10.17.

10.17. ,
-
//pxsem/prodcons4.c
72 void *
73 consume(void *arg)
74 {
75 int i;
76 for (;;) {
77
Sem_wait(&shared.nstored); /* */
78
Sem_wait(&shared.mutex);
79
if (shared.nget >= nitems) {
80
Sem_post(&shared.nstored);
81
Sem_post(&shared.mutex);
82
return(NULL); /* */
83
}
84
i = shared.nget % NBUFF;
85
if (shared.buff[i] != shared.ngetval)
86
printf("error: buff[%d] = %d\n", i, shared.buff[i]);
87
shared.nget++;
88
shared.ngetval++;
89
Sem_post(&shared.mutex);
90
Sem_post(&shared.nempty); /* */
91
*((int *) arg) += 1;
92 }
93 }

142

-
79-83 consume nget nitems, , ( produce).
, - , nstored. -,
nstored, -.
10.11.
, - ,

while ((n = read(fdin, buff, BUFFSIZE)) > 0) {


/* */
write(fdout, buff, n);
}
, , , , ,
. read write - fgets
fputs.
. 10.11 . reader , writer
. .

. 10.10. ,

143

. 10.11. ,
. 10.10 . . ,
5 , 7, 2 .
, , . 10.12. ( ),
. ,
, .

. 10.12.

( ) - .
, ,
. . 10.13 .

144

. 10.13.
, . ,
. ,
( ).
. , Unix
. ,
. ,
, .
( ) .
; . 10.14.

145

. 10.14.

, .
.
. 10.15 . 1,
, . 2,
1.
, .
, .
.
, , . 2
, 9 (. 10.10 10.13).
, ,
( streaming mode).

146

. 10.15.
, .
, . 10.11,
. , ( NBUFF). 10.18
main.

10.18.
main
//pxsem/mycat2.c
1 #include "unpipc.h"
2 #define NBUFF 8
3
4
5

struct { /* */
struct {
char data[BUFFSIZE]; /* */

147

6
ssize_t n; /* */
7
} buff[NBUFF]; /* */
8
sem_t mutex, nempty, nstored; /* , */
9 } shared;
10 int fd; /* , */
11 void *produce(void *), *consume(void *);
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

int
main(int argc, char **argv)
{
pthread_t tid_produce, tid_consume;
if (argc != 2)
err_quit("usage: mycat2 ");
fd = Open(argv[1], O_RDONLY);
/* */
Sem_init(&shared.mutex, 0, 1);
Sem_init(&shared.nempty, 0, NBUFF);
Sem_init(&shared.nstored, 0, 0);
/* , */
Set_concurrency(2);
Pthread_create(&tid_produce, NULL, produce, NULL); /* reader thread */
Pthread_create(&tid_consume, NULL, consume, NULL); /* writer thread */
Pthread_join(tid_produce, NULL);
Pthread_join(tid_consume, NULL);
Sem_destroy(&shared.mutex);
Sem_destroy(&shared.nempty);
Sem_destroy(&shared.nstored);
exit(0);
}


2-9 shared buff, . NBUFF .


18 , .
10.19 produce consume.

10.19. produce consume


//pxsem/mycat2.c
34 void *
35 produce(void *arg)
36 {
37 int i;
38 for (i = 0;;) {
39
Sem_wait(&shared.nempty); /* */
40
Sem_wait(&shared.mutex);
41
/* */
42
Sem_post(&shared.mutex);
43
shared.buff[i].n = Read(fd, shared.buff[i].data, BUFFSIZE);
44
if (shared.buff[i].n == 0) {
45
Sem_post(&shared.nstored); /* */
46
return(NULL);
47
}
48
if (++i >= NBUFF)

148

49
i = 0; /* */
50
Sem_post(&shared.nstored); /* */
51 }
52 }
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

void *
consume(void *arg)
{
int i;
for (i = 0;;) {
Sem_wait(&shared.nstored); /* */
Sem_wait(&shared.mutex);
/* */
Sem_post(&shared.mutex);
if (shared.buff[i].n == 0)
return(NULL);
Write(STDOUT_FILENO, shared.buff[i].data, shared.buff[i].n);
if (++i >= NBUFF)
i=0; /* */
Sem_post(&shared.nempty); /* */
}
}


40-42 , mutex, . ,
, . ,
-, . ,
, .

nstored
43-49 , , read. read nstored,
, . read 0 ( ) ,
.

-
57-68 - . , ,
. -, , mutex, .

22.3 [24] . SIGIO,


( dg_echo). nqueue.
SIGIO .
10.12.
: ( semt,
sem_init) , , ,
sem_init 1.

, - :
( pthread_mutex_t, pthread_cond_t pthread_rwlock_t)
PTHREAD_PROCESS SHARED.
, , sem_open.
, sem_open , , , ,
.
, sem_open, sem_t, fork? fork
Posix.1 , . ,
:

sem_t *mutex; /* , , fork() */

/* */
mutex = Sem_open(Px_ipc_name(NAME), O_CREAT | O_EXCL, FILE_MODE, 0);
if ((childpid = Fork()) == 0) {
/* */

149


Sem_wait(mutex);

}
/* */

Sem_post(mutex);

, , ,
sem_t, (, ).
, System V , semget. ,
, . System V ,
.
10.13.
Posix :
SEM_NSEMS_MAX (Posix ,
256);
SEM_VALUE_MAX (Posix , 32767).
sysconf, .
: semsysconf
10.20 sysconf , .

10.20. sysconf

//pxsem/semsysconf.
1 #include "unpipc.h"
2
3
4
5
6
7
8

int
main(int argc, char **argv)
{
printf("SEM_NSEMS_MAX = %ld, SEM_VALUE_MAX = %ld\n",
Sysconf(_SC_SEM_NSEMS_MAX), Sysconf(_SC_SEM_VALUE_MAX));
exit(0);
}

solaris % semsysconf
SEMS_NSEMS_MAX = 2147483647, SEM_VALUE_MAX = 2147483647
alpha % semsysconf
SEMS_NSEMS_MAX = 256, SEM_VALUE_MAX = 32767
10.14. FIFO
Posix FIFO. FIFO
. . sem_post 1 , a sem_wait
( , , ). sem_open FIFO,
O_CREAT; ( , ) FIFO
, .

, .
semaphore.h, sem_t ( 10.21).

10.21. semaphore.h
//my_pxsem_fifo/semaphore.h
1 /* */
2 typedef struct {
3
int sem_fd[2]; /* fd: [0] , [1] */
4
int sem_magic; /* */
5 } mysem_t;
6

#define SEM_MAGIC 0x89674523

150

7 #ifdef SEM_FAILED
8 #undef SEM_FAILED
9 #define
SEM_FAILED
*/

((mysem_t

*)(-1))

/*

10 #endif

sem_t
1-5 , FIFO, .
, , .
sem_magi SEM_MAGIC, . ,
sem_t, , ,
. 0. ,
.
sem_open
10.22 sem_open, .

10.22. sem_open
//my_pxsem_fifo/sem_open.
1 #include "unpipc.h"
2 #include "semaphore.h"
3 #include /* */
4 mysem_t *
5 mysem_open(const char *pathname, int oflag, )
6 {
7
int i, flags, save_errno;
8
char c;
9
mode_t mode;
10 va_list ap;
11 mysem_t *sem;
12 unsigned int value;
13 if (oflag & O_CREAT) {
14
va_start(ap, oflag); /* */
15
mode = va_arg(ap, va_mode_t);
16
value = va_arg(ap, unsigned int);
17
va_end(ap);
18
if (mkfifo(pathname, mode) < 0) {
19
if (errno == EEXIST && (oflag & O_EXCL) == 0)
20
oflag &= ~O_CREAT; /* , OK */
21
else
22
return(SEM_FAILED);
23
}
24 }
25 if ((sem = malloc(sizeof(mysem_t))) == NULL)
26
return(SEM_FAILED);
27 sem->sem_fd[0] = sem->sem_fd[1] = 1;
28 if ((sem->sem_fd[0] = open(pathname, O_RDONLY | O_NONBLOCK)) < 0)
29
goto error;
30 if ((sem->sem_fd[1] = open(pathname, O_WRONLY | O_NONBLOCK)) < 0)
31
goto error;
32 /* sem_fd[0] */
33 if ((flags = fcntl(sem->sem_fd[0], F_GETFL, 0)) < 0)
34
goto error;
35 flags &= ~O_NONBLOCK;
36 if (fcntl(sem->sem_fd[0], F_SETFL, flags) < 0)
37
goto error;

151

38 if (oflag & O_CREAT) { /* */


39
for (i = 0; i < value; i++)
40
if (write(sem->sem_fd[1], &c, 1) != 1)
41
goto error;
42 }
43 sem->sem_magic = SEM_MAGIC;
44 return(sem);
45 error:
46 save_errno = errno;
47 if (oflag & O_CREAT)
48
unlink(pathname); /* FIFO */
49 close(sem->sem_fd[0]); /* */
50 close(sem->sem_fd[1]); /* */
51 free(sem);
52 errno = save_errno;
53 return(SEM_FAILED);
54 }

s
13-17 O_CREAT, , . va_start,
(oflag). va_arg
. va_mode_t 5.17.

FIFO
18-23 FIFO, . 4.6,
EEXIST, . sem_open O_EXCL , ;
, O_CREAT.

sem_t FIFO

25-37 sem_t, . FIFO: ,
. open, O_NONBLOCK
( . 4.1). O_NONBLOCK ,
( , , PIPE_BUF).
, .


38-42 , , FIFO value . value
PIPE_BUF, write FIFO EAGAIN.
sem_close
sem_close 10.23.
11-15 , sem_t.

10.23. sem_close
//my_pxsem_fifo/sem_close.
1 #include "unpipc.h"
2 #include "semaphore.h"
3
4
5
6
7
8

int
mysem_close(mysem_t *sem)
{
if (sem->sem_magic != SEM_MAGIC) {
errno = EINVAL;
return(-1);

152

9
}
10 sem->sem_magic = 0; /* */
11 if (close(sem->sem_fd[0]) == 1 || close(sem->sem_fd[1]) == 1) {
12
free(sem);
13
return(-1);
14 }
15 free(sem);
16 return(0);
17 }
sem_unl ink
sem_unlink, 10.24, . unlink.

10.24. sem_unlink
//my_pxsem_fifo/sem_unlink.
1 #include "unpipc.h"
2 #include "semaphore.h"
3
4
5
6
7

int
mysem_unlink(const char *pathname)
{
return(unlink(pathname));
}

sem_ post
10.25 sem_post, .
11-12 FIFO. , ,
read .

10.25. sem_post
//my_pxsem_fifo/sem_post.
1 #include "unpipc.h"
2 #include "semaphore.h"
3
4
5
6
7
8
9
10
11
12
13
14

int
mysem_post(mysem_t *sem)
{
char c;
if (sem->sem_magic != SEM_MAGIC) {
errno = EINVAL;
return(-1);
}
if (write(sem->sem_fd[1], &c, 1) == 1)
return(0);
return(-1);
}

sem_wait
Posix sem_wait. 10.26.

10.26. sem_wait
//my_pxsem_fifo/sem_wait.
1 #include "unpipc.h"
2 #include "semaphore.h"
3
4
5

int
mysem_wait(mysem_t *sem)
{

153

6
char c;
7
if (sem->sem_magic != SEM_MAGIC) {
8
errno = EINVAL;
9
return(-1);
10 }
11 if (read(sem->sem_fd[0], &c, 1) == 1)
12
return(0);
13 return(-1);
14 }
11-12 1 FIFO, , .
sem_trywait, ,
read. sem_getvalue. stat fstat
, st_size stat. Posix ,
, . Posix
.
10.15.
Posix
Posix. , , .11.3 IEEE 1996 [8].

12 13. , .
semaphore.h ( 10.27), sem_t.

sem_t
1-7 , ,
. 10.21, sem_magi SEM_MAGIC .

10.27. semaphore.h
//my_pxsem_mmap/semaphore.h
1 /* */
2 typedef struct {
3
pthread_mutex_t sem_mutex; /*
*/
4
pthread_cond_t sem_cond; /* */
5
unsigned int sem_count; /* */
6
int sem_magic; /* , */
7 } mysem_t;
8

#define SEM_MAGIC 0x67458923

9 #ifdef SEM_FAILED
10 #undef SEM_FAILED
11 #define
SEM_FAILED
*/
12 #endif

((mysem_t

*)(-1))

/*

sem_open
10.28 sem_open,
.

10.28. sem_open:
//my_pxsem_mmap/sem_open.
1 #include "unpipc.h"
2 #include "semaphore.h"
3 #include /* */
4 #define MAX_TRIES 10 /* */
5
6
7

mysem_t *
mysem_open(const char *pathname, int oflag, )
{

154

8
int fd, i, created, save_errno;
9
mode_t mode;
10 va_list ap;
11 mysem_t *sem, seminit;
12 struct stat statbuff;
13 unsigned int value;
14 pthread_mutexattr_t mattr;
15 pthread_condattr_t cattr;
16 created = 0;
17 sem = MAP_FAILED; /* [sic] */
18 again:
19 if (oflag & O_CREAT) {
20
va_start(ap, oflag); /*
*/
21
mode = va_arg(ap, va_mode_t) & ~S_IXUSR;
22
value = va_arg(ap, unsigned int);
23
va_end(ap);
24
/* O_EXCL user-execute */
25
fd = open(pathname, oflag | O_EXCL | O_RDWR, mode | S_IXUSR);
26
if (fd < 0) {
27
if (errno == EEXIST && (oflag & O_EXCL) == 0)
28
goto exists; /* . OK */
29
else
30
return(SEM_FAILED);
31
}
32
created = 1;
33
/* , */
34
/* */
35
bzero(&seminit, sizeof(seminit));
36
if (write(fd, &seminit, sizeof(seminit)) != sizeof(seminit))
37
goto err;
38
/* */
39
sem = mmap(NULL, sizeof(mysem_t), PROT_READ | PROT_WRITE,
40
MAP_SHARED, fd, 0);
41
if (sem == MAP_FAILED)
42
goto err;
43
/* , ,
*/
44
if ((i = pthread_mutexattr_init(&mattr)) != 0)
45
goto pthreaderr;
46
pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
47
i = pthread_mutex_init(&sem->sem_mutex, &mattr);
48
pthread_mutexattr_destroy(&mattr); /* */
49
if (i != 0)
50
goto pthreaderr;
51
if ((i = pthread_condattr_init(&cattr)) != 0)
52
goto pthreaderr;
53
pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
54
i = pthread_cond_init(&sem->sem_cond, &cattr);
55
pthread_condattr_destroy(&cattr); /* */
56
if (i != 0)
57
goto pthreaderr;
58
if ((sem->sem_count = value) > sysconf(_SC_SEM_VALUE_MAX)) {
59
errno = EINVAL;
60
goto err;
61
}
62
/* , user-execute */
63
if (fchmod(fd, mode) == 1)
64
goto err;

155

65
66
67
68

close(fd);
sem->sem_magic = SEM_MAGIC;
return(sem);
}


19-23 O_CREAT, , .
va_mode_t 5.17, , .
user-execute mode (S_IXUSR) , . ,
user-execute.



24-32 O_CREAT ,
sem_t, . 5.17, ,
. , 10.37.


33-37 , . ,
0, write, ftruncate, , 13.3, Posix
, ftruncate .


38-42 mmap. sem_t, ,
, , mmap, read write.

sem_t
43-57 sem_t: , .
Posix , ,
PTHREAD_PROCESS_SHARED. ,
, pthread_mutexattr_init, ,
pthread_mutexattr_setpshared, pthread_mutex_init.
. , , .


58-61 .
, sysconf ( 10.13).

user-execute
62-67 user-execute. , .
close, .
10.29 sem_open. , ,
5.19.

10.29. sem_open:
//my_pxsem_mmap/sem_open.
69 exists:
70
if ((fd = open(pathname, O_RDWR)) < 0) {
71
if (errno == ENOENT && (oflag & O_CREAT))
72
goto again;
73
goto err;

156

74
}
75
sem = mmap(NULL, sizeof(mysem_t), PROT_READ | PROT_WRITE,
76
MAP_SHARED, fd, 0);
77
if (sem == MAP_FAILED)
78
goto err;
79
/* , */
80
for (i = 0; i < MAX TRIES; i++) {
81
if (stat(pathname, &statbuff) == 1) {
82
if (errno == ENOENT && (oflag & O_CREAT)) {
83
close(fd);
84
goto again;
85
}
86
goto err;
87
}
88
if ((statbuff.st_mode & S_IXUSR) == 0) {
89
close(fd);
90
sem->sem_magic = SEM_MAGIC;
91
return(sem);
92
}
93
sleep(1);
94
}
95
errno = ETIMEDOUT;
96
goto err;
97 pthreaderr:
98
errno = i;
99 err:
100 /* unlink munmap errno */
101 save_errno = errno;
102 if (created)
103
unlink(pathname);
104 if (sem != MAP_FAILED)
105
munmap(sem, sizeof(mysem_t));
106 close(fd);
107 errno = save_errno;
108 return(SEM_FAILED);
109 }


69-78 , O_CREAT, , .
. open ,
mmap.

, Posix.1 , .
, , .
sem_open . , (, ),
. sem_t,
. , ( ,
sem_close, ),
. (. 1.4), fork,
.

,
79-96 , (
). stat ( st_mode stat). user-execute ,
.


97-108 .
sem_close

157

10.30 sem_close, munmap .


, sem_open, SIGSEGV.

10.30. sem_close
//my_pxsem_mmap/sem_close.
1 #include "unpipc.h"
2 #include "semaphore.h"
3
4
5
6
7
8
9
10
11
12
13

int
mysem_close(mysem_t *sem)
{
if (sem->sem_magic != SEM_MAGIC) {
errno = EINVAL;
return(-1);
}
if (munmap(sem, sizeof(mysem_t)) == 1)
return(-1);
return(0);
}

sem_unl ink
sem_unlink 10.31. , , unlink.

10.31. sem_unlink
//my_pxsem_mmap/sem_unlink.
1 #include "unpipc.h"
2 #include "semaphore.h"
3
4
5
6
7
8
9

int
mysem_unlink(const char *pathname)
{
if (unlink(pathname) == 1)
return(-1);
return(0);
}

sem_post
10.32 sem_post, , ,
.

10.32. sem_post
//my_pxsem_mmap/sem_post.
1 #include "unpipc.h"
2 #include "semaphore.h"
3 int
4 mysem_post(mysem_t *sem)
5 {
6
int n;
7
if (sem->sem_magic != SEM_MAGIC) {
8
errno = EINVAL;
9
return(-1);
10 }
11 if ((n = pthread_mutex_lock(&sem->sem_mutex)) != 0) {
12
errno = n;
13
return(-1);

158

14 }
15 if (sem->sem_count == 0)
16
pthread_cond_signal(&sem->sem_cond);
17 sem->sem_count++;
18 pthread_mutex_unlock(&sem->sem_mutex);
19 return(0);
20 }
11-18 , . 0
1, pthread_cond_signal, ,
.
sem_wait
10.33 sem_wait, 0 ,
1.

10.33. sem_wait
//my_pxsem_mmap/sem_wait.
1 #include "unpipc.h"
2 #include "semaphore.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

int
mysem_wait(mysem_t *sem)
{
int n;
if (setn->sem_magic != SEM_MAGIC) {
errno = EINVAL;
return(-1);
}
if ((n = pthread_mutex_lock(&sem->sem_mutex)) != 0) {
errno = n;
return(-1);
}
while (sem->sem_count == 0)
pthread_cond_wait(&sem->sem_cond, &sem->sem_mutex);
sem->sem_count--;
pthread_mutex_unlock(&sem->sem_mutex);
return(0);
}

11-18 , . 0,
pthread_cond_wait , pthread_cond_signal ,
0 1. , 1 .
sem_trywait
10.34 sem_trywait, sem_wait.
11-22 . , 1
0. 1, errno EAGAIN.

10.34. sem_trywait
//my_pxsem_nmap/sem_trywait.
1 #include "unpipc.h"
2 #include "semaphore.h"
3 int
4 mysem_trywait(mysem_t *sem)
5 {
6
int n, rc;
7
if (sem->sem_magic != SEM_MAGIC) {
8
errno = EINVAL;
9
return(-1);
10 }

159

11 if ((n = pthread_mutex_lock(&sem->sem_mutex)) != 0) {
12
errno = n;
13
return(-1);
14 }
15 if (sem->sem_count > 0) {
16
sem->sem_count--;
17
rc = 0;
18 } else {
19
rc = 1;
20
errno = EAGAIN;
21 }
22 pthread_mutex_unlock(&sem->sem_mutex);
23 return(rc);
24 }
sem_getvalue
10.35 sem_getvalue. .
11-16 .

10.35. sem_getvalue
//my_pxsem_mmap/sem_getvalue.c
1 #include "unpipc.h"
2 #include "semaphore.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

int
mysem_getvalue(mysem_t *sem, int *pvalue)
{
int n;
if (sem->sem_magic != SEM_MAGIC) {
errno = EINVAL;
return(-1);
}
if ((n = pthread_mutex_lock(&sem->sem_mutex)) != 0) {
errno = n;
return(-1);
}
*pvalue = sem->sem_count;
pthread_mutex_unlock(&sem->sem_mutex);
return(0);
}

, , .
10.16. System V
Posix System V.
System V , Posix, ,
.

System V 11. , 11 .
, , semaphore.h ( 10.36), sem_t.

10.36. semaphore.h
//my_pxsem_svsem/semaphore.h
1 /* */
2 typedef struct {
3
int sem_semid; /* System V */
4
int sem_magic; /* , */
5 } mysem_t;
6

#define SEM_MAGIC 0x45678923

160

7
8
9
10

#ifdef SEM_FAILED
#undef SEM_FAILED
#define SEM_FAILED ((mysem_t *)(-1)) /* */
#endif

11 #ifndef SEMVMX
12 #define SEMVMX
System V */
13 #endif

32767

/*

sem_t
1-5 Posix System V, .
System V ( 10.21).
sem_open
10.37 sem_open, .

10.37. sem_open:
//my_pxsem_svsem/sem_open.
1 #include "unpipc.h"
2 #include "semaphore.h"
3 #include /* */
4 #define MAX_TRIES 10 /* */
5 mysem_t *
6 mysem_open(const char *pathname, int oflag, )
7 {
8
int i, fd, semflag, semid, save_errno;
9
key_t key;
10 mode_t mode;
11 va_list ap;
12 mysem_t *sem;
13 union semun arg;
14 unsigned int value;
15 struct semid_ds seminfo;
16 struct sembuf initop;
17 /* sem_open() O_CREAT ; */
18 semflag = SVSEM_MODE;
19 semid = 1;
20 if (oflag & O_CREAT) {
21
va_start(ap, oflag); /*
*/
22
23
24
25
26
27
28
29
30
31
32
33
34
35

mode = va_arg(ap, va_mode_t);


value = va_arg(ap, unsigned int);
va_end(ap);
/* , System V */
if ((fd = open(pathname, oflag, mode)) == 1)
return(SEM_FAILED);
close(fd);
if ((key = ftok(pathname, 0)) == (key_t) 1)
return(SEM_FAILED);
semflag = IPC_CREAT | (mode & 0777);
if (oflag & O_EXCL)
semflag |= IPC_EXCL;
/* System V IPC_EXCL */
if ((semid = semget(key, 1, semflag | IPC_EXCD) >= 0) {

161

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

/* OK, , */
arg.val = 0;
if (semctl(semid, 0, SETVAL, arg) == 1)
goto err;
/* , sem_otime */
if (value > SEMVMX) {
errno = EINVAL;
goto err;
}
initop.sem_num = 0;
initop.sem_op = value;
initop.sem_flg = 0;
if (semop(semid, &initop, 1) == 1)
goto err;
goto finish;
} else if (errno != EEXIST || (semflag & IPC_EXCL) != 0)
goto err:
/* */
}



20-24 O_CREAT, , , .
va_mode_t 5.17.


System V IPC
25-30 , . , ftok
. oflag, , open ,
, , EEXIST, O_EXCL.
, ftok, System V
IPC ( 3.2).

System V

32-33 O_CREAT O_EXCL System V I_ semget


System V, . IPC_EXCL , ,
.


34-50 11.2 , System V, 11.6 ,
. . , (,
IPC_EXCL), 0 SETVAL semctl,
semop. , sem_otime semget
0 semop. , , , ,
, sem_otime 0.


40-44 , , System V
(unsigned short, sem 11.1) 32767 ( 11.7), Posix
( 10.13). SEMVMX System
V, , 32 767 10.36.
52-53 O_EXCL, .
( ) .
10.38 sem_open.

162

10.38. sem_open:
//my_pxsem_svsem/sem_open.c
55 /*
56
* (O_CREAT )
57
* (O_CREAT O_EXCL ).
58
* , .
59
*/
60 if ((key = ftok(pathname, 0)) == (key_t) 1)
61
goto err;
62 if ((semid = semget(key, 0, semflag)) == 1)
63 goto err;
64 arg.buf = &seminfo;
65 for (i = 0; i < MAX_TRIES; i++) {
66
if (semctl(semid, 0, IPC_STAT, arg) == 1)
67
goto err;
68
if (arg.buf->sem_otime != 0)
69
goto finish;
70
sleep(1);
71 }
72 errno = ETIMEDOUT;
73 err:
74 save_errno = errno; /* semctl() errno */
75 if (semid != 1)
76
semctl(semid, 0, IPC_RMID);
77 errno = save_errno;
78 return(SEM_FAILED);
79 finish:
80 if ((sem = malloc(sizeof(mysem_t))) == NULL)
81
goto err;
82 sem->sem_semid = semid;
83 sem->sem_magic = SEM_MAGIC;
84 return(sem);
85 }


55-63 ( O_CREAT , O_EXCL, ), System V
semget. , sem_open mode , O_CREAT, semget
, . (
SVSEM_MODE unpipc.h) , semget, O_CREAT.


64-72 , , semctl IPC_STAT sem_otime
.


73-78 , , errno.

sem_t
79-84 sem_t System V.
.
sem_close
10.39 sem_close, free sem_t .

163

10.39. sem_close
//my_pxsem_svsem/sem_close.
1 #include "unpipc.h"
2 #include "semaphore.h"
3
4
5
6
7
8
9
10
11
12
13

int
mysem_close(mysem_t *sem)
{
if (sem->sem_magic != SEM_MAGIC) {
errno = EINVAL;
return(-1);
}
sem->sem_magic = 0; /* */
free(sem);
return(0);
}

sem_ unlink
sem_unlink, 10.40, System V,
Posix.

10.40. sem_unlink
//my_pxsem_svsem/sem_unlink.
1 #include "unpipc.h"
2 #include "semaphore.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

int
mysem_unlink(const char *pathname)
{
int semid;
key_t key;
if ((key = ftok(pathname, 0)) == (key_t) 1)
return(-1);
if (unlink(pathname) == 1)
return(-1);
if ((semid = semget(key, 1, SVSEM_MODE)) == 1)
return(-1);
if (semctl(semid, 0, IPC_RMID) == 1)
return(-1);
return(0);
}

System V
8-16 ftok System V IPC. unlink (
, , ). System V semget
IPC_RMID semctl.
sem_post
10.41 sem_post, .
11-16 semop , 1.

10.41. sem_post
//my_pxsem_svsem/sem_post.
1 #include "unpipc.h"
2 #include "semaphore.h"

164

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

int
mysem_post(mysem_t *sem)
{
struct sembuf op;
if (sem->sem_magic != SEM_MAGIC) {
errno * EINVAL;
return(-1);
}
op.sem_num = 0;
op.sem_op = 1;
op.sem_flg = 0;
if (semop(sem->sem_semid, &op, 1) < 0)
return(-1);
return(0);
}

sem_wait
10.42; sem_wait ,
1.
11-16 semop , 1.

10.42. sem_wait
//my_pxsem_svsem/sem_wait.c
1 #include "unpipc.h"
2 #include "semaphore.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

int
mysem_wait(mysem_t *sem)
{
struct sembuf op;
if (sem->sem_magic != SEM_MAGIC) {
errno = EINVAL;
return(-1);
}
op.sem_num = 0;
op.sem_op = 1;
op.sem_flg = 0;
if (semop(sem->sem_semid, &op, 1) < 0)
return(-1);
return(0);
}

sem_trywait
10.43 sem_trywait, sem_wait.
13 sem_wait 10.42 , sem_flg IPC_NOWAIT.
, semop EAGAIN, ,
sem_trywait, .

10.43. sem_trywait
//my_pxsem_svsem/sem_trywait.c
1 #include "unpipc.h"
2 #include "semaphore.h"
3
4
5
6
7

int
mysem_trywait(mysem_t *sem)
{
struct sembuf op;
if (sem->sem_magic != SEM_MAGIC) {

165

8
errno = EINVAL;
9
return(-1);
10 }
11 op.sem_num = 0;
12 op.sem_op = 1;
13 op.sem_flg = IPC_NOWAIT;
14 if (semop(sem->sem_semid, &op, 1) < 0)
15
return(-1);
16 return(0);
17 }
sem_getvalue
10.44. sem_getvalue, .
11-14 GETVAL semctl.

10.44. sem_getvalue
//my_pxsem_svsem/sem_getvalue.
1 #include "unpipc.h"
2 #include "semaphore.h"
3
4
5
6
7
8
9
10
11
12
13
14
15

int
mysem_getvalue(mysem_t *sem, int *pvalue)
{
int val;
if (sem->sem_magic != SEM_MAGIC) {
errno = EINVAL;
return(-1);
}
if ((val = semctl(sem->sem_semid, 0, GETVAL)) < 0)
return(-1);
*pvalue = val;
return(0);
}

10.17.
Posix -, :
1. .
2. .
3. 1 , .
Posix ( ).
, .
: ,
.
.
- -; ,
. ,
.
Posix. ,
FIFO, ( read write).
( Posix 5.8), ( ).
System V , , .

1. produce consume 10.6 . Sem_wait ,


( 10.6). printf Sem_wait, ,
. printf Sem_wait, , .
, , , .
2. , , my_lock 10.10:

% lockpxsem & lockpxsem & lockpxsem & lockpxsem &


initflag, 0, sem_open O_CREAT.
?
3. , my_lock, my_unlock?
4. 10.22, 1?
5. 10.22 errno, , :

if (sem->fd[0] >= 0) close(sem->fd[0]);


if (sem->fd[1] >= 0) close(sem->fd[1]);
6. , sem_open FIFO ( 10.22) ,
O_CREAT 5? () 10?

166

7. 10.28 10.29 ,
. 10.22 . .
8. Posix.1 semwait:
EINTR. , , .
, FIFO ( 10.14), ( 10.15)
System V ( 10.16).
9. sem_post async-signal-safe (. 5.1)?
10. 10.6 , mutex pthread_mutex_t,
. ?
11. ( 10.8 10.9) ( 10.11).
11
System V
11.1.
10 , :
, : 0 1.
( 7), 0 , 1 .
:
-, 0 , , Posix, 32767.
,
.
wait
1. post 1, , .
System V :
- , .
( 25 11.7). System V, -,
Posix, -.
, :

struct semid_ds {
struct ipc_perm sem_perm; /* */
struct sem *sem_base; /* */
ushort sem_nsems; /* */
time_t sem_otime; /* semop(); */
time_t sem_ctime; /* IPC_SET */
};
ipc_perm 3.3. .
sem , .
:

struct sem {
ushort_t semval; /* , */
short sempid; /* PID , semop(), SETVAL, SETALL */
ushort_t semncnt; /* ,
*/
ushort_t semzcnt; /* ,
0*/
};
, sem_base sem
.
: ,
, , , , ,
.

Unix 98 . (sem) System V.


semid_ds, sem.
, , . 11.1. sem_nsems 2,
([0] [1]).

. 11.1.
11.2. semget
semget .

#include
int semget(key_t key, int nsems, int oflag);

167

/* , 1
*/
, , semop semctl.
nsems . , ,
. .
oflag SEM_R SEM_A . 3.3. R Read (), Alter ().
IPC_CREAT IPC_CREAT | IPC_EXCL, . 3.2.
semid_ds:
uid cuid sem_perm , guid cgid
;
- oflag sem_perm.mode;
sem_otime 0, sem_ctime ;
sem_nsems nsems;
sem . semctl SETVAL SETALL.

1990 ,
semget . ,
. System V , ,
.
.
X/Open XPG3 (1989) Unix 98 ,
semget, semctl ( ) SETVAL (
) SETALL ( ).
(semget) (semctl)
System V. , IPC_CREAT | IPC_EXCL semget, ,
semget , , .
semget EEXIST, semget, IPC_CREAT
IPC_EXCL.
. ,
, :

1 oflag = IPC_CREAT | IPC_EXCL | SVSEM_MODE;


2 if ((semid = semget(key, 1, oflag)) >= 0) { /* ,
*/
3 arg.val = 1;
4 Semctl(semid, 0, SETVAL, arg);
5 } else if (errno == EEXIST) { /* ,
*/
6 semid = Semget(key, 1, SVSEM_MODE);
7 } else
8 err_sys("semget error");
9 Semop(semid, ); /* 1 */
:
1. 1-3, .
2. , 1, 2, 5, 6 9.
, , , ,
, ( 9),
. 9 .

Posix , sem_open.
, O_CREAT, ,
.
- . (,
10.12) .
. ( 10.10) ,
: , , ,
.
, . , sem_otime
semid_ds . ( System V , XPG3 Unix 98.)
semop. ,
semctl IPC_STAT semget ( 6). sem_otime
, , . ,
semop, .
10.37 11.6.
11.3. semop
semget
semop:

#include
int semop(int semid, struct sembuf *opsptr, size_t nops);
/* 0 , 1 */
opsptr

struct
short
short
short
};

sembuf {
sem_num; /* : 0, 1, nsems-1 */
sem_op; /* : <0, 0, >0 */
sem_flg; /* : 0, IPC_NOWAIT, SEM_UNDO */

168

sembuf, opsptr, nops.


. sen_num 0 , 1
. ., nsems-1, nsems ( semget ).

. ,
.

struct sembuf ops[2] = {


0, 0, 0, /* , */
0, 1, SEM_UNDO /* [0] 1 */
};
, :

struct sembuf ops[2];


ops[0].sem_num = 0; /* , */
ops[0].sem_op = 0;
ops[0].sem_flg = 0;
ops[1].sem_num = 0; /* [0] 1 */
ops[1].sem_op = 1;
ops[1].sem_flg = SEM_UNDO;
, semop, ; .
. 11.5.
sem_op, , . ,
:
semval (. 11.1);
semncnt , , (. 11.1);
semzcnt , , (. 11.1);
semadj . ,
SEM_UNDO sem_flg sembuf. SEM_UNDO ;
semadj ;
( ,
, ), ,
semop EINTR. , [24, . 124], , semop
, ;

, semop EIDRM (identifier removed ).
semop sem_op: , .
1. sem_op , semval. , .
SEM_UNDO, sem_op semadj .
2. semop , , (semval) . semval
0, .
semval , semzcnt ,
semval ( semzcnt 1). , ,
IPC_NOWAIT. ,
.
3. sem_op , ,
sem_op. .
semval sem_op, sem_op semval. SEM_UNDO, sem_op
semadj .
semval sem_op, semncnt , ,
semval semop. , , sem_op semval
semncnt . SEM_UNDO, sem_op semadj .
, , IPC_NOWAIT. ,
.

, Posix, , 1
(sem_wait) +1 (sem_post). System V , 1, , ,
. ,
System V , Posix.
11.4. semctl
semctl .

#include
int semctl(int semid, int semnum, int cmd, /* union semun arg */);
/*
). 1 */

(.

(semid) , a semnum (0, 1 . . nsems 1).


semnum GETVAL, SETVAL, GETNCNT, GETZCNT GETPID.
cmd (. ).
:

union semun {
int val; /* SETVAL */
struct semid_ds *buf; /* IPC_SET IPC_STAT */
ushort *array; /* GETALL SETALL */
};
(
unpipc.h, B.1). , , , .

169

, (FreeBSD Linux) ,
. , Unix 98 ,
.
cmd. 0, 1,
- .
GETVAL semval. (semval unsigned
short ), .
SETVAL semval arg.val. (semadj)
.
GETPID sempid.
GETNCNT semncnt.
GETZCNT semzcnt.
GETALL semval . arg.array,
0. ,
, , arg.array .
SETALL semval . arg.array.
IPC_RMID , semid.
IPC_SET semid_ds arg.buf: sem_perm.uid, sem_perm.gid
sem_perm.mode. sem_ctime semid_ds .
IPC_STAT arg.buf semid_ds
. , semid_ds arg.buf.
11.5.
System V , , ,
.
.
semcreate
, 11.1,[1] System V.
IPC_EXCL semget, .

11.1. semcreate
//svsem/semcreate.
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

int
main(int argc, char **argv)
{
int , oflag, semid, nsems;
oflag = SVSEM_MODE | IPC_CREAT;
while ((c = Getopt(argc, argv, "e")) != 1) {
switch (c) {
case 'e':
oflag |= IPC_EXCL;
break;
}
}
if (optind != argc 2)
err_quit("usage: semcreate [ e ] ");
nsems = atoi(argv[optind + 1]);
semid = Semget(Ftok(argv[optind], 0), nsems, oflag);
exit(0);
}

semrmid
, 11.2, . semctl
( cmd) IPC_RMID.

11.2. semrmid
//svsem/semrmid.c
1 #include "unpipc.h"
2
3
4
5

int
main(int argc, char **argv)
{
int semid;

170

6
if (argc != 2)
7
err_quit("usage: semrmid "):
8
semid = Semget(Ftok(argv[1], 0), 0, 0);
9
Semctl(semid, 0, IPC_RMID);
10 exit(0);
11 }
semsetvalues
semsetvalues ( 11.3) .


11-15 semget semctl IPC_STAT,
semid_ds . sem_nsems .


19-24 , ,
. semctl SETALL .

11.3. semsetvalues
//svsem/semsetvalues.
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5
int semid, nsems, i;
6
struct semid_ds seminfo;
7
unsigned short *ptr;
8
union semun arg;
9
if (argc < 2)
10
err_quit("usage: semsetvalues [ values ]");
11 /* */
12 semid = Semget(Ftok(argv[1], 0), 0, 0);
13 arg.buf = &seminfo;
14 Semctl(semid, 0, IPC_STAT, arg);
15 nsems = arg.buf->sem_nsems;
16 /* */
17 if (argc != nsems + 2)
18 err_quit("%d semaphores in set, %d values specified", nsems, argc-2);
19 /* ,
*/
20 ptr = Calloc(nsems, sizeof(unsigned short));
21 arg.array = ptr;
22 for (i = 0; i < nsems; i++)
23
ptr[i] = atoi(argv[i +2]);
24 Semctl(semid, 0, SETALL, arg);
25 exit(0);
26 }
semgetvalues
11.4 semgetvalues, .


11-15 semget semctl IPC_STAT
semi d_ds . sem_nsems .

171


16-22 , . semctl GETALL
. .

11.4. semgetvalues
//svsem/semgetvalues.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

int
main(int argc, char **argv)
{
int semid, nsems, i;
struct semid_ds seminfo;
unsigned short *ptr;
union semun arg;
if (argc != 2)
err_quit("usage: semgetvalues ");
/* */
semid = Semget(Ftok(argv[1], 0), 0, 0);
arg.buf = &seminfo;
Semctl(semid, 0, IPC_STAT, arg);
nsems = arg.buf->sem_nsems;
/* */
ptr = Calloc(nsems, sizeof(unsigned short));
arg.array = ptr;
/* */
Semctl(semid, 0, GETALL, arg);
for (i = 0; i < nsems; i++)
printf("semval[%d] = %d\n", i, ptr[i]);
exit(0);
}

semops
11.5 semops, .


7-19 n IPC_NOWAIT , u
SEM_UNDO. , semop sembuf
( ), .


20-29 semget sembuf,
. , .


30 semop .

11.5. semops
//svsem/semops.c
1 #include "unpipc.h"

172

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

int
main(int argc, char **argv)
{
int , i, flag, semid, nops;
struct sembuf *ptr;
flag = 0;
while ((c = Getopt(argc, argv, "nu")) != 1) {
switch (c) {
case 'n':
flag |= IPC_NOWAIT; /* */
break;
case 'u':
flag |= SEM_UNDO; /* */
break;
}
}
if (argc = optind < 2) /* argc optind = */
err_quit("usage: semops [ n ] [ u ] operation ");
semid = Semget(Ftok(argv[optind], 0), 0, 0);
optind++;
nops = argc optind;
/* , */
ptr = Calloc(nops, sizeof(struct sembuf));
for (i = 0; i < nops; i++) {
ptr[i].sem_num = i;
ptr[i].sem_op = atoi(argv[optind + i]); /* <0, 0, or >0 */
ptr[i].sem_flg = flag;
}
Semop(semid, ptr, nops);
exit(0);
}

System V:

solaris %
solaris %
solaris %
solaris %
semval[0]
semval[1]
semval[2]

touch /tmp/rich
semcreate e /tmp/rich 3
semsetvalues /tmp/rich 1 2 3
semgetvalues /tmp/rich
= 1
= 2
= 3

/tmp/rich, ftok .
semcreate . semsetvalues (1, 2 3), a semgetvalues .
:

solaris % semops n /tmp/rich 1 2 4


semctl error: Resource temporarily unavailable
solaris % semgetvalues /tmp/rich
semval[0] = 1
semval[1] = 2
semval[2] = 3
, (-n), ,
. ( 1 , 1),
( 2 , 2), (
4 , 3).
, EAGAIN. ,
, . ,
. , ,
. semop , , .
SEM_UNDO:

solaris % semsetvalues /tmp/rich 1 2 3


solaris % semops u /tmp/rich -1 2 3

SEM_UNDO
solaris % semgetvalues /tmp/rich

173

semval[0]

semops
semval[1]
semval[2]
solaris %
solaris %
semval[0]
semval[1]
semval[2]

= 2
= 3
semops /tmp/rich -1 2 3
semgetvalues /tmp/rich
= 0
= 0
= 0

SEM_UNDO

1, 2 3 semsetvalues,
semops 1, 2, 3. , , u semops,
SEM_UNDO. semadj 1, 2 3
. semops ,
1, 2 3, . , semgetvalues. semops, u,
, .
11.6.
System V my_lock my_unlock 10.10.
11.6.

11.6.
System V
//lock/locksvsem.c
1 #include "unpipc.h"
2 #define LOCK_PATH "/tmp/svsemlock"
3 #define MAX_TRIES 10
4 int semid, initflag;
5 struct sembuf postop, waitop;
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

void
my_lock (int fd)
{
int oflag, i;
union semun arg;
struct semid_ds seminfo;
if (initflag == 0) {
oflag = IPC_CREAT | IPC_EXCL | SVSEM_MODE;
if ((semid = semget(Ftok(LOCK_PATH, 0), 1, oflag)) >= 0) {
/* , */
arg.val = 1;
Semctl(semid, 0, SETVAL, arg);
} else if (errno == EEXIST) {
/* , , */
semid = Semget(Ftok(LOCK_PATH, 0), 1, SVSEM_MODE);
arg.buf = &seminfo;
for (i = 0; i < MAX_TRIES; i++) {
Semctl(semid, 0, IPC_STAT, arg);
if (arg.buf->sem_otime != 0)
goto init;
sleep(1);
}
err_quit("semget OK, but semaphore not initialized");
} else
err_sys("semget error");
init:
initflag = 1;
postop.sem_num = 0; /* semop()*/
postop.sem_op = 1;
postop.sem_flg = SEM_UNDO;

174

36
waitop.sem_num = 0;
37
waitop.sem_op = 1;
38
waitop.sem_flg = SEM_UNDO;
39 }
40 Semop(semid, &waitop, 1); /* 1 */
41 }
42
43
44
45
46

void
my_unlock(int fd)
{
Semop(semid, &postop, 1); /* 1*/
}


13-17 , , semget IPC_CREAT |
IPC_EXCL. , semctl 1.
my_lock, (, )
.

,
18-20 semget EEXIST, semget , IPC_CREAT IPC_EXCL.


21-28 , 11.2,
System V . , , , semctl IPC_STAT,
sem_otime . , ,
semop ( ) . (
), sleep, .
, .

sembuf
33-38 , sembuf , .
,
my_lock . SEM_UNDO, , ,
(. 10.3).
( , ,
), . ,
, .
. , .
11.7. System V
System V , , .
System V ( 3.8). . 11.1. System V
, oaee.
11.1. System V

semmni
semmsl
semmns
semopm
semmnu
semume
semvmx
semaem




semop
undo
undo

DUnix 4.0B Solaris 2.6


16
10
25
25
400
60
10
10
30
10
10
32767
32767
16384
16384

Digital Unix 4.0B semmnu .

11.7 , . 11.1.

175

11.7.
System V
//svsem/limits.c
1
#include "unpipc.h"
2
3
4
5
6
7

/* , */
#define MAX_NIDS 4096 /* */
#define MAX_VALUE 1024*1024 /* */
#define MAX_MEMBERS 4096 /* */
#define MAX_NOPS 4096 /* semop */
#define MAX_NPROC Sysconf(_SC_CHILD_MAX)

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

int
main(int argc, char **argv)
{
int i, j, semid, sid[MAX_NIDS], pipefd[2];
int semmni, semvmx, semmsl, semmns, semopn, semaem, semume, semmnu;
pid_t *child;
union semun arg;
struct sembuf ops[MAX_NOPS];
/* ? */
for (i = 0; i <= MAX_NIDS; i++) {
sid[i] = semget(IPC_PRIVATE, 1, SVSEM_MODE | IPC_CREAT);
if (sid[i] == 1) {
semmni = i;
printf("%d identifiers open at once\n", semmni);
break;
}
}
/* , sid[0] */
for (j = 7; j < MAX_VALUE; j += 8) {
arg.val = j;
if (semctl(sid[0], 0, SETVAL, arg) == 1) {
semvmx = j 8;
printf("max semaphore value = %d\n", semvmx);
break;
}
}
for (j = 0; j < i; j++)
Semctl(sid[j], 0, IPC_RMID);
/* */
for (i = 1; i <= MAX_MEMBERS; i++) {
semid = semget(IPC_PRIVATE, i, SVSEM_MODE | IPC_CREAT);
if (semid == 1) {
semmsl = i-1;
printf("max of %d members per set\n", semmsl);
break;
}
Semctl(semid, 0, IPC_RMID);
}
/* ? */
semmns = 0;
for (i = 0; i < semmni; i++) {
sid[i] = semget(IPC_PRIVATE, semmsl, SVSEM_MODE | IPC_CREAT);
if (sid[i] == 1) {
/*

176

52
semmsl ,
53
1 .
54

55
*/
56
for (j = semmsl-1; j > 0; j--) {
57
sid[1] = semget(IPC_PRIVATE, j, SVSEM_MODE | IPC_CREAT);
58
if (sid[i] != 1) {
59
semmns += j;
60
printf("max of %d semaphores\n", semmns);
61
Semctl(sid[i], 0, IPC_RMID);
62
goto done;
63
}
64
}
65
err_quit("j reached 0, semmns = %d", semmns);
66
}
67
semmns += semmsl;
68
}
69
printf("max of %d semaphores\n", semns);
70 done:
71
for (j = 0; j < i; j++)
72
Semctl(sid[j], 0, IPC_RMID);
73
/* semop() */
74
semid = Semget(IPC_PRIVATE, semmsl, SVSEM_MODE | IPC_CREAT);
75
for (i = 1; i <= MAX_NOPS; i++) {
76
ops[i-1].sem_num = i-1;
77
ops[i-1].sem_op = 1;
78
ops[i-1].sem_flg = 0;
79
if (semop(semid, ops, i) += 1) {
80
if (errno != E2BIG)
81
err_sys("expected E2BIG from semop");
82
semopn = i-1;
83
printf("max of %d operations per semop()\n", semopn);
84
break;
85
}
86
}
87
Semctl(semid, 0, IPC_RMID);
88
/* semadj */
89
/* */
90
semid = Semget(IPC_PRIVATE, 1, SVSEM_MODE | IPC_CREAT);
91
arg.val = semvmx;
92
Semctl(semid, 0, SETVAL, arg); /* */
93
for (i = semvmx-1; i > 0; i--) {
94
ops[0].sem_num = 0;
95
ops[0].sem_op = i;
96
ops[0].sem_flg = SEM_UNDO;
97
if (semop(semid, ops, 1) != 1) {
98
semaem = i;
99
printf("max value of adjust-on-exit = %d\n", semaem);
100
break;
101
}
102 }
103 Semctl(semid, 0, IPC_RMID);
104 /* UNDO */
105 /* */
106 semid = Semget(IPC_PRIVATE, 1, SVSEM_MODE | IPC_CREAT);
107 arg.val = 0;
108 Semctl(semid, 0, SETVAL, arg); /* 0 */
109 Pipe(pipefd);
110 child = Malloc(MAX_NPROC * sizeof(pid_t));

177

111 for (i = 0; i < MAX_NPROC; i++) {


112
if ((child[i] = fork()) == 1) {
113
semmnu = i 1;
114
printf("fork failed, semmnu at least %d\n", semmnu);
115
break;
116
} else if (child[i] == 0) {
117
ops[0].sem_num = 0; /* semop() */
118
ops[0].sem_op = 1;
119
ops[0].sem_flg = SEM_UNDO;
120
j = semop(semid, ops, 1); /* 0 . 1
*/
121
Write(pipefd[1], &j, sizeof(j));
122
sleep(30); /* */
123
exit(0); /* */
124
}
125
/* semop() */
126
Read(pipefd[0], &j, sizeof(j));
127
if (j == 1) {
128
semmnu = i;
129
printf("max # undo structures = %d\n", semmnu);
130
break;
131
}
132 }
133 Semctl(semid, 0, IPC_RMID);
134 for (j = 0; j <= i && child[j] > 0; j++)
135
Kill(child[j], SIGINT);
136 /* */
137 /* */
138 semid = Semget(IPC_PRIVATE, semmsl, SVSEM_MODE | IPC_CREAT);
139 for (i = 0; i < semmsl; i++) {
140
arg.val = 0;
141
Semctl(semid, i, SETVAL, arg); /* 0 */
142
ops[i].sem_num = i;
143
ops[i].sem_op = 1; /* 1 */
144
ops[i].sem_flg = SEM_UNDO;
145
if (semop(semid, ops, i+1) == 1) {
146
semume = i;
147
printf("max # undo entries per process = %d\n", semume);
148
break;
149
}
150 }
151 Semctl(semid, 0, IPC_RMID);
152 exit(0);
153 }
11.8.
System V Posix:
1. System V . ,
.
2. : ,
( , ). Posix
1 ( , ).
3. System V ,
, .
4. System V (undo) .

1. 6.6 6.4,
. , System V (
). 11.5 , System
V.
2. 11.6, LOCK_PATH ?
4

12

178

12.1.
.
, , . , ,
, . 3
: , , -, .

, , . ,
, , (
. .).
-,
(. 4.1).
. , .
, .
IPC .

, Posix ( mmap
), 5.8 12.2. . 12.1 , Posix ,
. System V
write msgsnd read msgrcv.
IPC, .
, ( write) .
, .
, ( ,
). . 12.1 .

. 12.1.
IPC ,
.
,
. , , .
, ,
. , .
:
, ();
. read ( ) ;
;
.

. 12.2.

. 12.2.
, :
. ; ,
, .
, Posix System V, . 13,
14.
, 9.
, .
, fork. poae 12.1 [1]
count.

179

12.1.

//shm/incr1.c
1 #include "unpipc.h"
2 #define SEM_NAME "mysem"
3 int count = 0;
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

int
main(int argc, char **argv)
{
int i, nloop;
sem_t *mutex;
if (argc != 2)
err_quit("usage: incr1 <#loops>");
nloop = atoi(argv[1]);
/* , */
mutex = Sem_open(Px_ipc_name(SEM_NAME), O_CREAT | O_EXCL, FILE_MODE, 1);
Sem_unlink(Px_ipc_name(SEM_NAME));
setbuf(stdout, NULL); /* stdout */
if (Fork() == 0) { /* */
for (i = 0; i < nloop; i++) {
Sem_wait(mutex);
printf("child: %d\n", count++);
Sem_post(mutex);
}
exit(0);
}
/* */
for (i = 0; i < nloop; i++) {
Sem_wait(mutex);
printf("parent: %d\r\", count++);
Sem_post(mutex);
}
exit(0);
}


12-14 , , (count).
, . , sem_unlink,
, . ,
.


fork
15 , , .
.
16-29 ,
.
, ,
, :

child:
child;

child;
child:

0
1

,count=

678
679

180

parent: 0

parent: 1

parent: 1220
parent: 1221
child: 680
,

child: 681

child: 2078
child: 2079
parent: 1222 ,

parent: 1223 . .
, count. 0
. . 12.3 fork.

. 12.3. fork

fork . . 12.4
fork.

. 12.4. fork

, count.
12.2. mmap, munmap msync
mmap Posix.
:
1. - ( 12.3).
2. ( 12.4 12.5).
3. shm_open Posix.

#include
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
/* .
MAP_FAILED */
addr , fd.
, .
, .
len ; ( ), ,
offset. offset = 0. . 12.5 .

181

. 12.5.
prot , . 12.1.
PROT_READ | PROT_WRITE, .

12.1. prot mmap

prot
PROT_READ
PROT_WRITE
PROT_EXEC
PROT_NONE

12.2. flag mmap

flag

MAP SHARED
MAP_PRIVATE

MAP_FIXED
addr
flags . 12.2. MAP_SHARED MAP_PRIVATE,
MAP_FIXED. MAP_PRIVATE,
; . MAP_SHARED, ,
.
poa MAP_FIXED . , addr
, . addr ,
. addr MAP_FIXED .
mmap MAP_SHARED
fork. Posix.1 , , ,
. , , , , .
.
munmap:

#include
int munmap(void *addr, size_t len);
/* 0 , 1 */
addr , mmap, a len . munmap
SIGSEGV (, mmap).
MAP_PRIVATE, .
. 12.5 , ,
( MAP_SHARED). ,
, . ,
. msync:

#include
int msync(void *addr, size_t len, int flags);
/* 0 , 1 */
flags . 12.3.

12.3. flags msync

MS_ASYNC


182

MS_SYNC

MS_INVALIDATE
MS_ASYNC MS_SYNC . ,
MS_ASYNC , , MS_SYNC
. MS_INVALIDATE, , ,
. .
?
, open,
mmap. , - , ,
. read, write lseek. .

Posix mmap, msg_hdr


( 5.26 5.28).
, , , . ,
, mmap. read write (
).
mmap .
, , (
IPC ). , mmap MAP_SHARED,
.

mmap [14] 4.4BSD [6] SVR4.


12.3.
12.1 ( ) ,
, . open mmap. 12.2
.

12.2.

//shm/incr2.c
1 #include "unpipc.h"
2 #define SEM_NAME "mysem"
3 int
4 main(int argc, char **argv)
5 {
6
int fd, i, nloop, zero = 0;
7
int *ptr;
8
sem_t *mutex;
9
if (argc != 3)
10
err_quit("usage: incr2 <#loops>");
11 nloop = atoi(argv[2]);
12 /* , */
13 fd = Open(argv[1], O_RDWR | O_CREAT, FILE_MODE);
14 Write(fd, &zero, sizeof(int));
15 ptr = Mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
16 Close(fd);
17 /* , */
18 mutex = Sem_open(Px_ipc_name(SEM_NAME), O_CREAT | O_EXCL, FILE_MODE, 1);
19 Sem_unlink(Px_ipc_name(SEM_NAME));
20 setbuf(stdout, NULL); /* stdout */
21 if (Fork() == 0) { /* */
22
for (i = 0; i < nloop; i++) {
23
Sem_wait(mutex);
24
printf("child: %d\n", (*ptr)++);
25
Sem_post(mutex);
26
}
27
exit(0);
28 }
29 /* */
30 for (i = 0; i < nloop; i++) {

183

31
Sem_wait(mutex);
32
printf("parent: %d\n", (*ptr)++);
33
Sem_post(mutex);
34 }
35 exit(0);
36 }


11-14 , , .
, , , .

mmap
15-16 mmap . ,
. . .
MAP_SHARED, , .
, ptr.

fork
20-34 fork. ,
, ptr.
fork ,
. , mmap MAP_SHARED, ,
. ,
, , ( , ptr, sizeof (int)),
( ).
, , , ptr,
. :

solaris % incr2 /tmp/temp.110000


child: 0

child: 1

child: 128
child: 129
parent: 130 ,
parent: 131

parent: 636
parent: 637
child: 638
,
child: 639

child: 1517
child: 1518
parent: 1519 ,
parent: 1520

parent: 19999
solaris % od D /tmp/temp.1
0000000 0000020000
0000004
, od ,
(20000) .
. 12.6 , . 12.4. ,
. , Posix .
, .
, 10.15.

184

. 12.6.

, ptr,
, .
12.2 , Posix, ( ).
. 12.3.

12.3.

//shm/incr3.c
1 #include "unpipc.h"
2
3
4
5

struct shared {
sem_t mutex; /* : , */
int count; /* */
} shared;

6 int
7 main(int argc, char **argv)
8 {
9
int fd, i, nloop;
10 struct shared *ptr;
11 if (argc != 3)
12
err_quit("usage: incr3 <#loops>");
13 nloop = atoi(argv[2]);
14 /* , , */
15 fd = Open(argv[1], O_RDWR | O_CREAT, FILE_MODE);
16 Write(fd, &shared, sizeof(struct shared));
17 ptr = Mmap(NULL, sizeof(struct shared), PROT_READ | PROT_WRITE,
18
MAP_SHARED, fd, 0);
19 Close(fd);
20 /* , */
21 Sem_init(&ptr->mutex, 1, 1);
22 setbuf(stdout, NULL); /* stdout */
23 if (Fork() == 0) { /* */
24
for (i = 0; i < nloop; i++) {
25
Sem_wait(&ptr->mutex);
26
printf("child: %d\n", ptr->count++);
27
Sem_post(&ptr->mutex);
28
}
29
exit(0);
30 }

185

31 /* */
32 for (i = 0; i < nloop; i++) {
33
Sem_wait(&ptr->mutex);
34
printf("parent: %d\n", ptr->count++);
35
Sem_post(&ptr->mutex);
36 }
37 exit(0);
38 }

2-5 , , . .


14-19 , .
, sem_init.
, .


20-21 , , . sem_init.
, .
. 12.7 . 12.6, .

. 12.7. ,
12.4. 4.4BSD
12.2 12.3 , ( ),
open, write ( ). mmap
fork, , .
1. 4.4BSD .
. MAP_SHARED | MAP_ANON fd = 1. , offset, .
. 12.4.
2. SVR4 /dev/zero, mmap.
, . 12.5. ( ,
BSD, /dev/zero, SunOS 4.1.x BSD/OS 3.1.)
12.4 12.2, 4.4BSD.

12.4. 4.4BSD
//shm/incr_map_anon.
3 int
4 main(int argc, char **argv)
5 {
6
int i, nloop;
7
int *ptr;
8
sem_t *mutex;
9
if (argc != 2)
10
err_quit("usage: incr_map_anon <#loops>");

186

11
12
13
14

nloop = atoi(argv[1]);
/* */
ptr = Mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANON, 1, 0);

6-11 fd zero , , .
12-14 . MAP_ANON mmap, ()
1.
12.5. SVR4 /dev/zero
12.5 , 12.2
/dev/zero.

12.5. SVR4
/dev/zero
//shm/incr_dev_zero.c
3 int
4 main(int argc char **argv)
5 {
6
int fd, i, nloop;
7
int *ptr;
8
sem_t *mutex;
9
if (argc != 2)
10
err_quit("usage: incr_dev_zero <#loops>");
11 nloop = atoi(argv[1]);
12 /* /dev/zero */
13 fd = Open("/dev/zero", O_RDWR);
14 ptr = Mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
15 Close(fd);
6-11 zero , , .
12-15 /dev/zero mmap. .
12.6. ,
, ( mmap), , .
, 12.3 shared write
. , , .
mmap 12.6.

12.6. :

//shra/test1.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5
int fd, i;
6
char *ptr;
7
size_t filesize, mmapsize, pagesize;
8
if (argc != 4)
9
err_quit("usage: test1 ");
10 filesize = atoi(argv[2]);
11 mmapsize = atoi(argv[3]);
12 /* , */
13 fd = Open(argv[1], O_RDWR | O_CREAT | O_TRUNC, FILE_MODE);
14 Lseek(fd, filesize-1, SEEK_SET);
15 Write(fd, "", 1);
16 ptr = Mmap(NULL, mmapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
17 Close(fd);
18 pagesize = Sysconf(_SC_PAGESIZE);

187

19 printf("PAGESIZE = %ld\n", (long) pagesize);


20 for (i = 0; i < max(filesize, mmapsize); i += pagesize) {
21
printf("ptr[*d] = %d\n", i, ptr[i]);
22
ptr[i] = 1;
23
printf("ptr[%d] = %d\n", i + pagesize 1, ptr[i + pagesize 1]);
24
ptr[i + pagesize 1] = 1;
25 }
26 printf("ptr[%d] = %d\n", i, ptr[i]);
27 exit(0);
28 }


8-11 , .

, , ;

12-15 , . , .
lseek , e- 1 1 .


16-17 , . .


18-19 sysconf .


20-26 , .
. . 1.
, . for
, poa ( ).
: ,
:

solaris % ls l foo
foo: No such file or directory
solaris % test1 foo 5000 5000
PAGESIZE = 4096
ptr[0] = 0
ptr[4095] = 0
ptr[4096] = 0
ptr[8191] = 0
Segmentation Fault(coredump)
solaris % ls-l foo
-rw-r--r-- 1 rstevens other1 5000 Mar 20 17:18 foo
solaris % od b A d foo
0000000 001 000 000 000 000 000 000 000 000 000 000
0000016 000 000 000 000 000 000 000 000 000 000 000
*
0004080 000 000 000 000 000 000 000 000 000 000 000
0004096 001 000 000 000 000 000 000 000 000 000 000
0004112 000 000 000 000 000 000 000 000 000 000 000
0005000

000 000 000 000 000


000 000 000 000 000
000 000 000 000 001
000 000 000 000 000
000 000 000 000 000

4096 , ( 4096-8191),
(8192) SIGSEGV, Segmentation Fault.

188

ptr[8191] = 1, 5000 .
, ( ),
. ( 0, 4095 4096) , ,
od ( b ,
Ad ). . 12.8 .

. 12.8.

Digital Unix 4.0B, , 8192 :

alpha % ls l foo
foo not found
alpha % test1 foo5000 5000
PAGESIZE = 8192
ptr[0] = 0
ptr[8191] = 0
Memory fault (coredump)
alpha % ls -l foo
-rw-r-r 1 rstevens operator 5000 Mar 21 08:40 foo
, a ( 5000 8191).
ptr[8192] SIGSEGV, .
: (15000 ) (5000 ):

solaris % rm foo
solaris % test1 foo 5000 15000
ptr[0] = 0
ptr[4095] = 0
ptr[4096] = 0
ptr[8191] = 0
Bus Error(coredump)
solaris % ls l foo
-rw-r-r 1 rstevens other1 5000 Mar 20 17:37 foo

. 12.9.
, (5000 ).
SIGBUS ( Bus Error),
SIGSEGV. , SIGBUS a , a SIGSEGV
a . , , ,
. mmap , ,
( , 5000 8191 ). . 12.9
.

189

12.7. :
, (
), , .

12.7.

//shm/test2.c
1 #include "unpipc.h"
2 #define FILE "test.data"
3 #define SIZE 32768
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

int
main(int argc, char **argv)
{
int fd, i;
char *ptr;
/* , , , mmap */
fd = Open(FILE, O_RDWR | O_CREAT | O_TRUNC, FILE_MODE);
ptr = Mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
for (i = 4096; i <= SIZE; i += 4096) {
printf("setting file size to %d\n", i);
Ftruncate(fd, i);
printf("ptr[%d] = %d\n", i-1, ptr[i-1]);
}
exit(0);
}


9-11 , , , .
32 768 , .


12-16 4096 ftruncate ( 13.3) .
, :

alpha % ls l test.data
test.data: No such file or directory
alpha % test2
setting file size to 4096
ptr[4095] = 0
setting file size to 8192
ptr[8191] = 0
setting file size to 12288
ptr[12287] = 0
setting file size to 16384
ptr[16383] = 0
setting file size to 20480
ptr[20479] = 0
setting file size to 24576
ptr[24575] = 0
setting file size to 28672
ptr[28671] = 0
setting file size to 32768
ptr[32767] = 0
alpha % ls-l test.data

190

-rw-r--r-- 1 rstevens other1 32768 Mar 20 17:53 test.data


, ( test.data),
, , .
Solaris 2.6.
mmap. 13.1
Posix, .
12.7.
IPC,
, . , ,
.
mmap ,
.
read, write lseek , ,
mmap. .
fork, ,
. Berkeley mmap MAP_ANON, SVR4
/dev/zero.
, mmap, ,
, , mmap Posix, .
Posix :
mlockall ; munlockall ;
mlock . .
munlock .

1. 12.7, for?
2. , , . System V.
. , Posix
5.8, .
3. , mmap MAP_SHARED
. , /dev/zero, , ,
.
4. 12.2, MAP_PRIVATE MAP_SHARED. , ,
12.1. , ?
5. 6.9 , select System V
, msgrcv, .
, , ,
. select
. , .
my_shm ( .31).
msgcreate msgsnd 6.6.
.
13
Posix
13.1.
, , mmap.
, mmap , .
:
( 12.2);
4.4BSD ( 12.4);
/dev/zero ( 12.5).
, , .
Posix.1 :
1. : open, mmap
. 12,
. .
2. : shm_open IPC Posix (,
), , mmap.
.
mmap. , mmap:
open, shm_open. . 13.1. Posix (memory objects)
, Posix.
13.2. sh m_ open shm_ unlink
Posix :
1. shm_open IPC , .

. 13.1. Posix:
2. mmap .
, shm_open, ,
.

191

, ,
, , mmap , Posix. ,
. shm_open (, mq_open
mqd_t, a sem_open sem_t), mmap
.

#include
int shm_open(const char *name, int oflag, mode_t mode);
/* , -1
*/
int shm_unlink(const char *name);
/* 0 , -1 */
, name, 2.2.
oflag O_RDONLY O_RDWR : O_CREAT, O_EXCL, O_TRUNC. O_CREAT O_EXCL
2.3. O_RDWR O_TRUNC, .
mode (. 2.3) O_CREAT. ,
mq_open sem_open shm_open mode . O_CREAT , mode
.
shm_open , mmap
.
shm_unlink . ( ,
Posix), ,
. shm_unlink open, mq_open sem_open .
13.3. ftrun cate fstat
ftruncate:

#include
int ftruncate(int fd, off_t length);
/* 0 , 1 */
Posix .
1. : length, .
length, . :
1 seek length-1 1 . , Unix ftruncate.
2. : ftruncate length.
, ftruncate
. fstat :

#include
#include
int fstat(int fd, struct stat *buf);
/* 0 . 1 */
stat ( 4 [21]),
, fd :

struct stat {

mode_t st_mode; /* mode: S_I{RW}{USR,GRP,OTH} */


uid_t st_uid; /* UID */
gid_t st_gid; /* GID */
off_t st_size; /* */

};
.

, Posix . shm_open ,
. ftruncate , ( )
. . Posix.1 (Rationale)
, , .
comp.std.unix, , -
. - ( ),
.
13.4.
, Posix.
sh mcreate
shmcreate, 13.1,[1] .

13.1.
Posix
//pxshm/shmcreate.c
1 #include "unpipc.h"
2

int

192

3 main(int argc, char **argv)


4 {
5
int c, fd, flags;
6
char *ptr;
7
off_t length;
8
flags = O_RDWR | O_CREAT;
9
while ((c = Getopt(argc, argv, "e")) != 1) {
10
switch (c) {
11
case 'e':
12
flags |= O_EXCL;
13
break;
14
}
15 }
16 if (optind != argc 2)
17
err_quit("usage: shmcreate [ e ] ");
18 length = atoi(argv[optind + 1]);
19 fd = Shm_open(argv[optind], flags, FILE_MODE);
20 Ftruncate(fd, length);
21 ptr = Mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
22 exit(0);
23 }
19-22 shm_open . , ,
. ftruncate ( ), a mmap .
. Posix , .
sh munl ink
13.2 , .

13.2.
Posix
//pxshm/shmunlink.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9

int
main(int argc, char **argv)
{
if (argc != 2)
err_quit("usage: shmunlink ");
Shm_unlink(argv[1]);
exit(0);
}

shmwrite
13.3 shmwrite, 0, 1, 2 254, 244, 0, 1 . . .

13.3.
//pxshm/shmwrite.
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5
int i, fd;
6
struct stat stat;
7
unsigned char *ptr;
8
if (argc != 2)
9
err_quit("usage: shmwrite ");
10 /* open, , */

193

11 fd = Shm_open(argv[1], O_RDWR, FILE_MODE);


12 Fstat(fd, &stat);
13 ptr = Mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE,
14
MAP_SHARED, fd, 0);
15 Close(fd);
16 /* : ptr[0] = 0, ptr[1] = 1 . . */
17 for (i = 0; i < stat.st_size; i++)
18
*ptr++ = i % 256;
19 exit(0);
20 }
10-15 shm_open. fstat.
mmap, .
16-18 .
sh mread
shmread ( 13.4) , shmwrite.

13.4.

//pxshm/shmread.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

int
main(int argc, char **argv)
{
int i, fd;
struct stat stat;
unsigned char c, *ptr;
if (argc != 2)
err_quit("usage: shmread ");
/* open, , */
fd = Shm_open(argv[1], O_RDONLY, FILE_MODE);
Fstat(fd, &stat);
ptr = Mmap(NULL, stat.st_size, PROT_READ,
MAP_SHARED, fd, 0);
Close(fd);
/* ptr[0] = 0, ptr[1] = 1 . . */
for (i = 0; i < stat.st_size; i++)
if ((c = *ptr++) != (i % 256))
err_ret("ptr[%d] = %d", i, c);
exit(0);
}

10-15 , fstat,
, .
16-19 , shmwrite.

/tmp/myshm 123 456 Digital Unix 4.0B:

alpha % shmcreate /tmp/myshm 123456


alpha % ls l /tmp/myshm
-rw-r--r-- 1 rstevens system 123456 Dec 10 14:33 /tmp/myshm
alpha % od c /tmp/myshm
0000000 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
*
0361100
, . od,
, ( 0361100 , ,
, 123 456).
shmwrite od:

alpha % shmwrite /tmp/myshm


alpha * od x /tmp/myshm | head-4
0000000 0100 0302 0504 0706 0908 0b0a 0d0c 0f0e

194

0000020
0000040
0000060
alpha %
alpha %

1110 1312 1514 1716 1918 1b1a 1d1c 1f1e


2120 2322 2524 2726 2928 2b2a 2d2c 2f2e
3130 3332 3534 3736 3938 3b3a 3d3c 3f3e
shmread /tmp/myshm
shmunlink /tmp/myshm

shmread, , shmunlink.
shmcreate Solaris 2.6, , /tmp:

solaris % shmcreate e /testshm 123


solaris % ls-l/tmp/.*testshm*
-rw-r--r-- 1 rstevens other1 123 Dec 10 14:40 /tmp/.SHMtestshm

( 13.5), , ,
.

13.5.

//pxshm/test3.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

int
main(int argc, char **argv)
{
int fd1, fd2, *ptr1, *ptr2;
pid_t childpid;
struct stat stat;
if (argc != 2)
err_quit("usage: test3 ");
shm_unlink(Px_ipc_name(argv[1]));
fd1 = Shm_open(Px_ipc_name(argv[1]), O_RDWR | O_CREAT | O_EXCL, FILE_MODE);
Ftruncate(fd1, sizeof(int));
fd2 = Open("/etc/motd", O_RDONLY);
Fstat(fd2, &stat);
if ((childpid = Fork()) == 0) {
/* */
ptr2 = Mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd2, 0);
ptr1 = Mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE,
MAP_SHARED, fd1, 0);
printf("child: shm ptr = %p, motd ptr = %p\n", ptr1, ptr2);
sleep(5);
printf("shared memory integer = %d\n", *ptr1);
exit(0);
}
/* : map */
ptr1 = Mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd1, 0);
ptr2 = Mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd2, 0);
printf("parent: shm ptr = %p, motd ptr = %p\n", ptr1, ptr2);
*ptr1 = 777;
Waitpid(childpid, NULL, 0);
exit(0);
}

10-14 , .
. /etc/motd.
15-30 fork , mmap , .
. 5 , 777 ,
.
, ,
:

solaris % test3 test3.data


parent: shm ptr = eee30000, motd ptr = eee20000

195

child: shm ptr = eee20000, motd ptr = eee30000


shared memory integer = 777
, 777 0xeee30000,
020000. ptr1
, .
13.5.
, 12.3, , .
, , .
, . Posix
Posix , , , . ,
IPC IPC (
).
13.6 -, , ,
.

13.6. ,

//pxshm/server1.c
1 #include "unpipc.h"
2
3
4
5

struct shmstruct { /* , */
int count;
};
sem_t *mutex; /* */

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

int
main(int argc, char **argv)
{
int fd;
struct shmstruct *ptr;
if (argc != 3)
err_quit("usage: server1 ");
shm_unlink(Px_ipc_name(argv[1])); /* */
/* shm. , , */
fd = Shm_open(Px_ipc_name(argv[1]), O_RDWR | O_CREAT | O_EXCL, FILE_MODE);
Ftruncate(fd, sizeof(struct shmstruct));
ptr = Mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
Close(fd);
sem_unlink(Px_ipc_name(argv[2])); /* */
mutex = Sem_open(Px_ipc_name(argv[2]), O_CREAT | O_EXCL, FILE_MODE, 1);
Sem_close(mutex);
exit(0);
}


13-19 shm_unlink, , ,
shm_open, . sbmstruct ftruncate, mmap
. .


20-22 sem_unlink, , . sem_open
. ,
. .

196


23 . Posix ,
, .
. ,
Posix IPC - , ( , , ). ,
Solaris .MQ, .SEM .SHM, Digital Unix .
13.7 -, , , ,
.

13.7. ,

//pxshm/client1.c
1 #include "unpipc.h"
2
3
4
5

struct shmstruct { /* , */
int count;
};
sem_t *mutex; /* */

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

int
main(int argc, char **argv)
{
int fd, i, nloop;
pid_t pid;
struct shmstruct *ptr;
if (argc != 4)
err_quit("usage: client1 <#loops>");
nloop = atoi(argv[3]);
fd = Shm_open(Px_ipc_name(argv[1]), O_RDWR, FILE_MODE);
ptr = Mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
Close(fd);
mutex = Sem_open(Px_ipc_name(argv[2]), 0);
pid = getpid();
for (i = 0; i < nloop; i++) {
Sem_wait(mutex);
printf("pid %ld: %d\n", (long) pid, ptr->count++);
Sem_post(mutex);
}
exit(0);
}


15-18 shm_open , ( O_CREAT).
mmap, .


19 .


20-26 .
, .

197

, - .

solaris % server shm1 sem1


solaris % client1 shm1 sem110000 &client1 shm1 sem110000 &client1 shm1 sem1 10000&
[2] 17976

[3] 17977
[4] 17978
pid 17977: 0

pid 17977: 1
. . .
17977
pid 17977: 32
pid 17976: 33

. . .
17976
pid 17976: 707
pid 17978: 708

. . .
17978
pid 17978: 852
pid 17977: 853

. . .
..
pid 17977: 29997
pid 17977: 29999 . .
13.6.
. ,
, . , ,
, syslog, 13 [24].
, ,
. , Telnet syslog, .
( 2) . , ,
- , , , . . 13.2
.

. 13.2.
() ().
.
13.8 cliserv2.h, , .

13.8. ,

//pxshm/cliserv2.h
1 #include "unpipc.h"
2 #define MESGSIZE 256 /*
*/
3 #define NMESG 16 /* */
4
5
6
7

struct
sem_t
sem_t
sem_t

shmstruct { /* , */
mutex; /* Posix, */
nempty;
nstored;

198

8
int nput; /* */
9
long noverflow; /* */
10 sem_t noverflowmutex; /* */
11 long msgoff[NMESG]; /* */
12 char msgdata[NMESG * MESGSIZE]; /* */
13 };


5-8 Posix, , ,
10.6. mutex, nempty, nstored. nput .
,
.


9-10 , - . -
(, FTP HTTP),
. - , , (noverflow).
, ,
.


11-12 msgoff msgdata, . ,
msgoff[0] = 0, msgoff [1] = 256 ( MESGSIZE), msgoff [2] = 512 . .
, ,
( ). mmap
. ,
.
13.9 -, , .

13.9. ,

//pxshm/server2.c
1 #include "cliserv2.h"
2 int
3 main(int argc, char **argv)
4 {
5
int fd, index, lastnoverflow, temp;
6
long offset;
7
struct shmstruct *ptr;
8
if (argc != 2)
9
err_quit("usage: server2 ");
10 /* , ,
, */
11 shm_unlink(Px_ipc_name(argv[1])); /* */
12 fd = Shm_open(Px_ipc_name(argv[1]), O_RDWR | O_CREAT | O_EXCL, FILE_MODE);
13 ptr = Mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE,
14
MAP_SHARED, fd, 0);
15 Ftruncate(fd, sizeof(struct shmstruct));
16 Close(fd);
17 /* */
18 for (index = 0; index < NMESG; index++)
19
ptr->msgoff[index] = index * MESGSIZE;
20 /* */
21 Sem_init(&ptr->mutex, 1, 1);
22 Sem_init(&ptr->nempty, 1, NMESG);

199

23 Sem_init(&ptr->nstored, 1, 0);
24 Sem_init(&ptr->noverflowmutex, 1, 1);
25 /* - */
26 index = 0;
27 lastnoverflow = 0;
28 for (;;) {
29
Sem_wait(&ptr->nstored);
30
Sem_wait(&ptr->mutex);
31
offset = ptr->msgoff[index];
32
printf("index = %d: %s\n", index, &ptr->msgdata[offset]);
33
if (++index >= NMESG)
34
index =0; /* */
35
Sem_post(&ptr->mutex);
36
Sem_post(&ptr->nempty);
37
Sem_wait(&ptr->noverflowmutex);
38
temp = ptr->noverflow; /* , */
39
Sem_post(&ptr->noverflowmutex);
40
if (temp != lastnoverflow) {
41
printf("noverflow = %d\n", temp);
42
lastnoverflow = temp;
43
}
44 }
45 exit(0);
46 }


10-16 shm_unlink, , .
shm_open mmap,
.


17-19 .


20-24 , . sem_init ,
.

,
25-36 for : nstored,
mutex, , nempty.


37-43 . noverflows .
, . ,
noverflowmutex, . ,
, . 13.10 -.

13.10. ,

//pxshm/client2.c
1 #include "cliserv2.h"

200

2 int
3 main(int argc, char **argv)
4 {
5
int fd, i, nloop, nusec;
6
pid_t pid;
7
char mesg[MESGSIZE];
8
long offset;
9
struct shmstruct *ptr;
10 if (argc != 4)
11
err_quit("usage: client2 <#loops> <#usec>");
12 nloop = atoi(argv[2]);
13 nusec = atoi(argv[3]);
14
/* ,
*/
15 fd = Shm_open(Px_ipc_name(argv[1]), O_RDWR, FILE_MODE);
16 ptr = Mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE,
17
MAP_SHARED, fd, 0);
18 Close(fd);
19 pid = getpid();
20 for (i = 0; i < nloop; i++) {
21
Sleep_us(nusec);
22
snprintf(mesg, MESGSIZE, "pid %ld; message %d", (long) pid, i);
23
if (sem_trywait(&ptr->nempty) == 1) {
24
if (errno == EAGAIN) {
25
Sem_wait(&ptr->noverflowmutex);
26
ptr->noverflow++;
27
Sem_post(&ptr->noverflowmutex);
28
continue;
29
} else
30
err_sys("sem_trywait error");
31
}
32
Sem_wait(&ptr->mutex);
33
offset = ptr->msgoff[ptr->nput];
34
if (++(ptr->nput) >= NMESG)
35
ptr->nput = 0; /* */
36
Sem_post(&ptr->mutex);
37
strcpy(&ptr->msgdata[offset], mesg);
38
Sem_post(&ptr->nstored);
39 }
40 exit(0);
41 }


10-13 ; ,
. ( ).
, .
, .


14-18 , , ,
. .


201

19-31 -, sem_wait(nempty),
, sem_trywait .
, EAGAIN. , .

sleep_us .9 .10 [21]. .


select poll.
32-37 mutex, (offset) nput,
. ,
.
, -, 50
:

solaris % server2 serv2 &


[2] 27223
solaris % client2 serv250 0
index = 0: pid 27224: message 0
index = 1: pid 27224: message 1
index = 2: pid 27224: message 2


index = 15: pid 27224: message 47
index = 0: pid 27224: message 48
index = 1: pid 27224: message 49
- , .

solaris % client2 serv250 0


index = 2: pid 27228: message 0
index = 3: pid 27228: message 1


index = 10: pid 27228: message 8
index = 11: pid 27228: message 9
noverflow = 25 25
index = 12: pid 27228: message 10
index = 13: pid 27228: message 11

12-22
index = 9: pid 27228: message 23
index = 10: pid 27228: message 24
0-9, .
10-49, 15, 25 ( 25 49) - :
, - , ,
, . . ,
, . , ,
, , .

. 8.13 [24]
UDP UDP. 18.2 [23] , Unix
ENOBUFS . UDP. -
13.10 , ,
, .
13.7.
Posix mmap, . shm_open
Posix IPC . , mmap.
, Posix .
,
ftruncate, ( , , ) fstat.
, Posix, (
5.8 10.15). Posix , .
( Solaris Digital Unix), shm_open open, a shm_unlink unlink.

1. 12.6 12.7 , Posix,


. , , .
2. for 13.3 13.4 *ptr++ . ptr[i]?
14
System V
14.1.
System V Posix. shm_open mmap
shmget shmat.
, :

struct shmid_ds {
struct ipc_perm shm_perm; /* */
size_t shm_segsz; /* */
pid_t shm_lpid; /* , */
pid_t shm_cpid; /* - */
shmatt_t shm_nattch; /* */

202

shmat_t shm_cnattch;
time_t shm_atime; /*
time_t shm_dtime; /*
time_t shm_ctime; /*
};

/* in-core */
*/
*/
*/

ipc_perm 3.3; .
14.2. shmget
shmget :

#include
int shmget(key_t key, size_t size, int oflag);
/* . 1
*/
. shmXXX.
key , ftok, IPC_PRIVATE, 3.2.
size . .
, size .
oflag . 3.3.
IPC_CREAT IPC_CREAT | IPC_EXCL, . 3.2.
.
, shmget , .
shmat, .
14.3. shmat
shmget
shmat:

#include
void *shmat(int shmid, const void *shmaddr, int flag);
/* . 1
*/
shmid , shmget. shmat
. , , :
shmaddr , .
( ) ;
shmaddr , , SHM_RND ( flag ):
SHM_RND , , shmaddr,
SHM_RND , , shmaddr,
SHMLBA. LBA lower boundary address .
, . flag
SHM_RDONLY, .
14.4. sh mdt
shmdt:

#include
int shmdt(const void *shmaddr);
/* 0 , 1 */
, , .
, . shmctl IPC_RMIO.
14.5. shmctl
shmctl :

#include
int shmctl(int shmid, int and, struct shmid_ds *buff);
/* 0 , 1 */
( cmd) :
IPC_RMID shmid ;
IPC_SET shmid_ds ,
buff: shm_perm.uid, shm_perm.gid, shm_perm.mode. shm_ctime
;
IPC_STAT ( buff) shmid_ds
.
14.6.
, System V.
sh mget
shmget, 14.1, [1] ,
.

14.1.
System V
//svshm/shmget.c
1 #include "unpipc.h"

203

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

int
main(int argc, char **argv)
{
int c, id, oflag;
char *ptr;
size_t length;
oflag = SVSHM_MODE | IPC_CREAT;
while ((c = Getopt(argc, argv, "e")) != 1) {
switch (c) {
case 'e':
oflag |= IPC_EXCL;
break;
}
}
if (optind != argc 2)
err_quit("usage: shmget [ e ] ");
length = atoi(argv[optind + 1]);
id = Shmget(Ftok(argv[optind], 0), length, oflag);
ptr = Shmat(id, NULL, 0);
exit(0);
}

19 shmget . , ,
IPC System V ftok. ,
. , , .
20 shmat . . System V
, .
sh mrmid
14.2 shmrmid, shmctl IPC_RMID
.

14.2.
system V
//svshm/shmrmid.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11

int
main(int argc, char **argv)
{
int id;
if (argc != 2)
err_quit("usage: shmrmid ");
id = Shmget(Ftok(argv[1], 0), 0, SVSHM_MODE);
Shmctl(id, IPC_RMID, NULL);
exit(0);
}

shmwrite
14.3 shmwrite, 0, 1, 2, , 254,
255, 0, 1 . .

14.3.

//svshm/shmwrite.c
1 #include "unpipc.h"
2

int

204

3 main(int argc, char **argv)


4 {
5
int i, id;
6
struct shmid_ds buff;
7
unsigned char *ptr;
8
if (argc != 2)
9
err_quit("usage: shmwrite ");
10 id = Shmget(Ftok(argv[1], 0), 0, SVSHM_MODE);
11 ptr = Shmat(id, NULL, 0);
12 Shmctl(id, IPC_STAT, &buff);
13 /* : ptr[0] = 0, ptr[1] = 1 . . */
14 for (i = 0; i < buff.shm_segsz; i++)
15
*ptr++ = i % 256;
16 exit(0);
17 }
10-12 shmget shmat. shmctl
IPC_STAT.
13-15 .
sh mread
shmread, 14.4, ,
shmwrite.

14.4.

//svshm/shmread.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

int
main(int argc, char **argv)
{
int i, id;
struct shmid_ds buff;
unsigned char c, *ptr;
if (argc != 2)
err_quit("usage: shmread ");
id = Shmget(Ftok(argv[1], 0), 0, SVSHM_MODE);
ptr = Shmat(id, NULL, 0);
Shmctl(id, IPC_STAT, &buff);
/* ptr[0] = 0, ptr[1] = 1 . . */
for (i = 0; i < buff.shm_segsz; i++)
if ((c = *ptr++) != (i % 256))
err_ret("ptr[%d] = %d", i.e);
exit(0);
}

10-12 . shmctl IPC_STAT. 13-16


, shmwrite.

1234 Solaris 2.6.


shmget. ftok.
:

solaris % shmget shmget 1234


solaris % ipcs bmo
IPC status from as of Thu Jan 8 13:17:06 1998
T ID KEY
MODE
OWNER
GROUP NATTCH SEGSZ
Shared Memory:
m 1 0x0000f12a rw-r--r-- rstevens other1 0
1234
ipcs , ,
shmcreate. ( shm_nattch shmid_ds) , .
poay shmwrite, .
shmread :

205

solaris % shmwrite shmget


solaris % shmread shmget
solaris % shmrmid shmget
solaris % ipes bmo
IPC status from as of Thu Jan 8 13:17:06 1998
T ID KEY
MODE
OWNER
GROUP NATTCH SEGSZ
Shared Memory:
ipcs, , .

ftok - IPC System V


(, /usr/bin/myserverd), , (shmget). ,
, . , ftok
i-node IPC , ( ).
14.7. ,
System V , System V (
3.8). . 14.1 . System V
, .

14.1. , System V

shmmax
shmmnb
shmmni
shmseg

DUnix
4.0B

4194304
1

128

,
32

Solaris
2.6
1048576
1
100
6

14.5 , . 14.1.

14.5.

//svshm/limits.c
1 #include "unpipc.h"
2 #define MAX_NIDS 4096
3 int
4 main(int argc, char **argv)
5 {
6
int i, j, shmid[MAX_NIDS];
7
void *addr[MAX_NIDS];
8
unsigned long size;
9
/* */
10 for (i = 0; i <= MAX_NIDS; i++) {
11
shmid[i] = shmget(IPC_PRIVATE, 1024, SVSHM_MODE | IPC_CREAT);
12
if (shmid[i]== 1) {
13
printf("%d identifiers open at once\n", i);
14
break;
15
}
16 }
17 for (j = 0; j < i; j++)
18
Shmctl(shmid[j], IPC_RMID, NULL);
19
/* */
20
for (i=0;i <= MAX_NIDS; i++) {
21
shmid[i] = Shmget(IPC_PRIVATE, 1024, SVSHM_MODE | IPC_CREAT);
22
addr[i] = shmat(shmid[i], NULL, 0);
23
if (addr[i] == (void *) 1) {
24
printf("%d shared memory segments attached at once\n", i);

206

*/

25

Shmctl(shmid[i], IPC_RMID, NULL); /*

26
break;
27
}
28
}
29
for (j = 0; j < i; j++) {
30
Shmdt(addr[j]);
31
Shmcfl(shmid[j], IPC_RMID, NULL);
32
}
33
/* */
34
for (size = 1; ; size++) {
35
shmid[0] = shmget(IPC_PRIVATE, size, SVSHM_MODE | IPC_CREAT);
36
if (shmid[0] != 1) { /* */
37
printf("minimum size of shared memory segment = %lu\n", size);
38
Shmctl(shmid[0], IPC_RMID, NULL);
39
break;
40
}
41 }
42 /* */
43 for (size = 65536; ; size += 4096) {
44
shmid[0] = shmget(IPC_PRIVATE, size, SVSHM_MODE | IPC_CREAT);
45
if (shmid[0] == 1) { /* */
46
printf("maximum size of shared memory segment = %lu\n", size-4096);
47
break;
48
}
49
Shmctl(shmid[0], IPC_RMID, NULL);
50 }
51 exit(0);
52 }
Digital Unix 4.0B, :

alpha % limits
127 identifiers open at once
32 shared memory segments attached at once
minimum size of shared memory segment = 1
maximum size of shared memory segment = 4194304
, . 14.1 128 , 127, ,
.
14.8.
System V Posix. :
shmget ;
shmat ;
shmctl IPC_STAT ;
shmctl IPC_RMID .
, Posix ftruncate (
13.1), System V shmget
.

6.6 6.4. IPC System V


. , System V
( ). 14.4, ,
System V.
5

15

15.1.
- . , . 15.1.

207

. 15.1.

1. (local procedure call) .


() . ,
, .
2. (remote procedure call RPC) ,
. , . . 15.1
. , ,
(doors). , () . () ,
, (), .
IPC, ( ) .
3. RPC , -
( . 15.1). 16.

Spring.
http://www.sun.com/tech/projects/spring. [7].
Solaris 2.5, , , ,
, Sun. Solaris 2.6 8
, . Solaris 2.6 API .
Linux , http://www.cs.brown.edu/~tor/doors.
Solaris 2.6, (-ldoor), door_XXX,
, (/kernel/sys/doorfs).
Solaris, ,
- . ,
, .
(synchronous): ,
. : (
pthread_create) .
pthread_join. , , ,
.
. .
door_create; , ,
. fattach.
open, , , ,
. door_call. , ,
, .
, : door_call,
, (, ). Solaris . ,
, -.
, , ,
, . , ,
. .
( ), ,
.
, .
. . , ,
. 15.8.

: ,
. 15.1 [1] - ( ,
).

15.1 .

208

//doors/client1.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int
main(int argc, char **argv)
{
int fd;
long ival, oval;
door_arg_t arg;
if (argc != 3)
err_quit("usage: client1 ");
fd = Open(argv[1], O_RDWR); /* */
/* */
ival = atol(argv[2]);
arg.data_ptr = (char *) &ival; /* */
arg.data_size = sizeof(long); /* */
arg.desc_ptr = NULL;
arg.desc_num = 0;
arg.rbuf = (char *) &oval; /* */
arg.rsize = sizeof(long); /* */
/* */
Door_call(fd, &arg);
printf("result: %ld\n", oval);
exit(0);
}


8-10 , . open.
, .


11-18 arg . data_ptr , a data_size
. desc_ptr desc_num ,
15.8. rbuf , a rsize .


19-21 door_call;
. .
- 15.2. servproc main.

15.2. ,

//doors/server1.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9

void
servproc(void *cookie, char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc)
{
long arg, result;
arg = *((long *) dataptr);
result = arg * arg;
Door_return((char *) &result, sizeof(result), NULL, 0);

209

10 }
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

int
main(int argc, char **argv)
{
int fd;
if (argc != 2)
err_quit("usage: server1 ");
/* */
fd = Door_create(servproc, NULL, 0);
unlink(argv[1]);
Close(Open(argv[1], O_CREAT | O_RDWR, FILE_MODE));
Fattach(fd, argv[1]);
/* servproc() */
for (;;)
pause();
}


2-10 , dataptr. .
, , .
door_return. , ,
.

17-21 door_create. , (servproc).


,
. ( unlink, ,
, ) fattach SVR4, .


22-24 pause. servproc,
.
:

solaris % server1 /tmp/server1


poay-e , , :

solaris % client1 /tmp/server19


result: 81
solaris % ls -l /tmp/server1
Drw-r-r 1 rstevens other1 0 Apr 9 10:09 /tmp/server1
. ls, , poaa D , , ,
.
. 15.2 aaa . door_call , door_return
.
. 15.3 aaa, , .

. 15.2.

210

. 15.3 :
0. , door_create, servproc,
.
1. door_call. .
2. door_call . , ,
-.
3. (servproc ).
4. door_return .
5. door_return , .
6. -, .

. 15.3.

(doors API) , . ,
IPC ( ).
15.2. door_call
door_call , -:

#include
int door_call(int fd, door_arg_t *argp);
/* 0 . 1 */
fd open (. 15.1). , ,
, door_call .
argp , :

typedef struct door_arg {


char *data_ptr; /* ,
*/
size_t data_size; /* ,
*/
door_desc_t *desc_ptr; /* -,
*/
size_t desc_num; /* -,
*/
char *rbuf; /* */
size_t rsize; /* */
} door_arg_t;
. ,
.

char*
. void*. char* door_return.
, Solaris 2.7 desc_num unsigned int door_return .
: .
- data_size . data_ptr.
( , ). . poaax
15.1 15.2 , ,
. ,
, . , ,

211

, . 15.8 15.9. -
, data_ptr data_size 0.

, ,
, - .
- door_desc_t, .
door_desc_t desc_num. ( 15.8.)
- , desc_ptr desc_num 0.
data_ptr -, a data_size .
, data_size 0, data_ptr .
, desc_ptr door_desc_t,
. door_desc_t desc_num.
, desc_num 0, desc_ptr .
. door_call data_ptr,
desc_ptr , rbuf.
door_call rbuf , a rsize .
data_ptr, desc_ptr . , ,
mmap ( 12.2) rbuf rsize
. data_ptr desc_ptr . ,
munmap rbuf rsize. 15.4.
15.3. door_create
- door_create:

#include
typedef void Door_server_proc(void *cookie, char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc);
int door_create(Door_server_proc *proc, void *cookie, u_int attr);
/* , 1
*/
, . ,
(, servproc 15.2) .
door_create, (proc) , ,
. cookie , door_create.
- , .
dataptr, datasize, descptr ndesc - - .
door_arg_t, .
door_create(attr) 0,
:
DOOR_PRIVATE - .
.
DOOR_PRIVATE , ,
.
DOOR_UNREF , , ,
, DOOR_UNREF_DATA. descptr , datasize ndesc
. 15.13.
void, return.
door_return ( ).
15.2 , door_create fattach
. ,
door_call.

fattach Posix.1, Unix 98. ,


fdetach, , fdetach, .
, door_create, FD_CLOEXEC. ,
exec. fork,
, . ,
, door_create, .

, PID ( door_info_t 15.6),


exec fork . ,
, . exec, ,
, exec.
15.4. door_return
door_return. door_call
.

#include
int door_return(char *dataptr, size_t datasize, door_desc_t *descptr, size_t
ndesc);
/* . 1
*/
dataptr datasize, descptr ndesc.
15.5. door_cred
.
door_cred:

#include
int door_cred(door_cred_t *cred);
/* 0 , 1 */
, cred, door_cred_t,

typedef struct door_cred {

212

uid_t dc_euid; /* */
gid_t dc_egid; /* */
uid_t dc_ruid; /* */
gid_t dc_rgid; /* */
pid_t dc_pid; /* */
} door_cred_t;
door_cred. 4.4 [21]
, . 15.5.
, . ,
, , .
15.6. door_info
door_cred . ,
doo_info:

#include
int door_info(int fd, door_info_t *info);
/* 0 , 1 */
fd . door_info_t, info,
:

typedef struct doo_info {


pid_t di_target; /* */
door_ptr_t di_proc; /* */
door_ptr_t di_data; /* */
door_attr_t di_attributes; /* , */
door_id_t di_uniquifier; /* */
} door info t;
di_target , a di_proc ( , ,
). , (cookie), di_data.
di_attributes, 15.3. DOOR_PRIVATE
DOOR_UNREF. DOOR_LOCAL ( ) DOOR_REVOKE (
, , door_revoke).
, di_uniquifier.
. ,
DOOR_QUERY. ,
. (di_proc di_data) .
15.7.
.
door_info
15.3 , door_inf ,
.

15.3.
//doors/doorinfo.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5
int fd;
6
struct stat stat;
7
struct door_info info;
8
if (argc != 2)
9
err_quit("usage; doorinfo ");
10 fd = Open(argv[1], O_RDONLY);
11 Fstat(fd, &stat);
12 if (S_ISDOOR(stat.st_mode) == 0)
13
err_quit("pathname is not a door");
14 Door_info(fd, &info);
15 printf("server PID = %ld, uniquifier = %ld",
16
(long)info.di_target, (long)info.di_uniquifier);
17 if (info.di_attributes & DOOR_LOCAL)
18
printf(", DOOR_LOCAL");
19 if (info.di_attributes & DOOR_PRIVATE)
20
printf(", DOOR_PRIVATE");

213

21 if (info.di_attributes & DOOR_REVOKED)


22
printf(", DOOR_REVOKED");
23 if (info.di_attributes & DOOR_UNREF)
24
printf(", DOOR_UNREF");
25 printf("\n");
26 exit(0);
27 }
, . st_mode stat
, S_ISDOOR . door_info.
, ,
Solaris 2.6:

solaris % doorinfo/etc/passwd
pathname is not a door
solaris % doorinfo /etc/.name_service_door
server PID = 308, uniquifier = 18, DOOR_UNREF
solaris % doorinfo /etc/.syslog_door
server PID = 282, uniquifier = 1635
solaris % ps f -p 308
root 308 1 0 Apr 01 ? 0:34 /usr/sbin/nscd
solaris % ps f -p 282
root 282 1 0 Apr 01 ? 0:10 /usr/sbin/syslogd n z 14
ps , , , door_info.

door_call, , ,
. . 15.4 -,
15.2.

15.4.
//doors/client2.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

int
main(int argc, char **argv)
{
int fd;
long ival, oval;
door_arg_t arg;
if (argc != 3)
err_quit("usage: client2 ");
fd = Open(argv[1], O_RDWR); /* */
/* */
ival = atol(argv[2]);
arg.data_ptr = (char *) &ival; /* - */
arg.data_size = sizeof(long); /* */
arg.desc_ptr = NULL;
arg.desc_num = 0;
arg.rbuf = (char *) &oval; /* */
arg.rsize = sizeof(long); /* */
/* */
Door_call(fd, &arg);
printf("&oval = %p, data_ptr = %p, rbuf = %p, rsize = %d\n",
&oval, arg.data_ptr, arg.rbuf, arg.rsize);
printf("result: %ld\n", *((long *) arg.data_ptr));
exit(0);
}

19-22 oval, data_ptr,


door_call , (rbuf rsize).
, 15.2. , data_ptr rbuf
oval rsize 4 (4 ). , :

solaris % client2 /tmp/server2 22

214

&oval = effff740, data_ptr = effff740, rbuf = effff740, rsize = 4


result: 484
15.4, . 18 :

arg.rsize = sizeof(long) 1; /* */
, data_ptr
:

solaris % client3 /tmp/server3 33


&oval = effff740, data_ptr = ef620000, rbuf = ef620000, rsize = 4096
result: 1089
4096 , , 12.6.
, data_ptr, , rbuf.
*(long*)arg.data_ptr, oval ( 15.2).
mmap munmap.
door_call.
door_cred
servproc 15.3, door_cred .
15.5 ; main 15.2
15.3.

15.5. ,

//doors/server4.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15

void
servproc(void *cookie, char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc)
{
long arg, result;
door_cred_t info;
/* */
Door_cred(&info);
printf("euid = %ld, ruid = %ld, pid = %ld\n",
(long) info.dc_euid, (long) info.dc_ruid, (long) info.dc_pid);
arg = *((long *) dataptr);
result = arg * arg;
Door_return((char *) &result, sizeof(result), NULL, 0);
}

- , , .
, SUID :

solaris % client4 /tmp/server4 77


result: 5929
solaris % su

Password:
Sun Microsystems Inc. Sun OS 5.6 Generic August 1997
solaris # cd
,
solaris # ls l client4
-rwxrwxr-x 1 rstevens other1 139328 Apr 13 06:02 client4
solaris
#
chown
root
client4

solaris # chmod u+s client4


SUID
solaris # ls -l client4

-rwsrwxr-x 1 root
other1 139328 Apr 13 06:02 client4
solaris # exit
solaris % ls -l client4
-rwsrwxr-x 1 root
other1 139328 Apr 13 06:02 client4
solaris % client4 /tmp/server477 -
result: 5929
, , :

solaris % server4 /tmp/server4

215

euid = 224, ruid = 224, pid = 3168


euid = 0, ruid = 224, pid = 3176
. 0 .

, , .
, . .
15.6 .

15.6. ,

//doors/server5.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12

void
servproc(void *cookie, char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc)
{
long arg, result;
arg = *((long *) dataptr);
printf("thread id %ld, arg = %ld\n", pr_thread_id(NULL), arg);
sleep(5);
result = arg * arg;
Door_return((char*)&result, sizeof(result), NULL, 0);
}

pr_thread_id. (
) ( ,
). . ,
(int long), , getpid, long ( 9.2).
pthread_t, . , Solaris 2.6
, Digital Unix .
( ). , 15.7,
.

15.7. pr_thread_id:

//lib/wrappthread.c
245 long
246 pr_thread_id(pthread_t *ptr)
247 {
248 #if defined(sun)
249 return((ptr == NULL) ? pthread_self() : *ptr); /* Solaris */
250 #elif defined(__osf__) && defined(__alpha)
251 pthread_t tid;
252 tid = (ptr == NULL) ? pthread_self() : *ptr; /* Digital Unix */
253 return(pthread_getsequence_np(tid));
254 #else
255 /* */
256 return((ptr == NULL) ? pthread_self() : *ptr);
257 #endif
258 }
, .
pthread_t .
thread_name [13].
15.6. . ,
, , :

solaris
result:
solaris
result:

% client5 /tmp/server5 55
3025
% client5 /tmp/server5 66
4356

216

solaris % client5 /tmp/server5 77


result: 5929
, , , :

solaris %
thread id
thread id
thread id

server5 /tmp/server5
4, arg = 55
4, arg = 66
4, arg = 77

- :

solaris % client5 /tmp/server5 11 & client5 /tmp/server5 22 & client5 /tmp/server5

33 &

[2] 3812
[3] 3813
[4] 3814
solaris % result: 484
result: 121
result: 1089
, :

thread id 4, arg = 22
thread id 5, arg = 11
thread id 6, arg = 33
( ):

solaris % client5 /tmp/server5 11 & client5 /tmp/server5 22 &


[2] 3830
[3] 3831
solaris % result: 484
result: 121
:

thread id 6, arg = 22
thread id 5, arg = 11
, ( , )
. , ,
15.9.
, (concurrent):
. ,
. ,
5 , 10, 15.
:
- . , , :
? , ,
, .
squareproc.h. , ,
. .
15.8.

15.8. squareproc.h
//doors/squareproc.h
1 #define PATH_SQUARE_DOOR "/tmp/squareproc_door"
2 typedef struct { /* squareproc() */
3 long arg1;
4 } squareproc_in_t;
5 typedef struct { /* squareproc() */
6 long res1;
7 } squareproc_out_t;
( double).
, sqrtproc.h 15.9.

15.9. sqrtproc.h
//doors/sqrtproc.h
1 #define PATH_SQRT_DOOR "/tmp/sqrtproc_door"

217

2 typedef struct { /* sqrtproc() */


3 long arg1;
4 } sqrtproc_in_t;
5 typedef struct { /* sqrtproc() */
6 double res1;
7 } sqrtproc_out_t;
- 15.10. .
, .

15.10. ,
//doors/client7.c
1 #include "unpipc.h"
2 #include "squareproc.h"
3 #include "sqrtproc.h"
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

int
main(int argc, char **argv)
{
int fdsquare, fdsqrt;
door_arg_t arg;
squareproc_in_t square_in;
squareproc_out_t square_out;
sqrtproc_in_t sqrt_in;
sqrtproc_out_t sqrt_out;
if (argc != 2)
err_quit("usage: client7 ");
fdsquare = Open(PATH_SQUARE_DOOR, O_ROWR);
fdsqrt = Open(PATH_SQRT_DOOR, O_RDWR);
/* squareproc() */
square_in.arg1 = atol(argv[1]);
arg.data_ptr = (char*)&square_in;
arg.data_size = sizeof(square_in);
arg.desc_ptr = NULL;
arg.desc_num = 0;
arg.rbuf = (char*)&square_out;
arg.rsize = sizeof(square_out);
Door_call(fdsquare, &arg);
/* sqrtproc() */
sqrt_in.arg1 = atol(argv[1]);
arg.data_ptr = (char*)&sqrt_in;
arg.data_size = sizeof(sqrt_in);
arg.desc_ptr = NULL;
arg.desc_num = 0;
arg.rbuf = (char*)&sqrt_out;
arg.rsize = sizeof(sqrt_out);
Door_call(fdsqrt, &arg);
printf("result: %ld %g\n", square_out.res1, sqrt_out.res1);
exit(0);
}

15.11. , 5- , .

15.11.
//doors/server7.c

218

1
2
3
4

#include "unpipc.h"
#include
#include "squareproc.h"
#include "sqrtproc.h"

5
6
7
8
9
10
11
12
13
14
15
16
17

void
squareproc(void *cookie, char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc)
{
squareproc_in_t in;
squareproc_out_t out;
memcpy(&in, dataptr, min(sizeof(in), datasize));
printf("squareproc: thread id %ld, arg = %ld\n",
pr_thread_id(NULL), in.arg1);
sleep(5);
out.res1 = in.arg1 * in.arg1;
Door_return((char *) &out, sizeof(out), NULL, 0);
}

18
19
20
21
22
23
24
25
26
27
28
29
30

void
sqrtproc(void *cookie, char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc)
{
sqrtproc_in_t in;
sqrtproc_out_t out;
memcpy(&in, dataptr, min(sizeof(in), datasize));
printf("sqrtproc: thread id %ld, arg = %ld\n",
pr_thread_id(NULL), in.arg1);
sleep(5);
out.res1 = sqrt((double)in.arg1);
Door_return((char *) &out, sizeof(out), NULL, 0);
}

main , 15.12,
.

15.12. main
//doors/server7.c
31 int
32 main(int argc, char **argv)
33 {
34 int fd;
35 if (argc != 1)
36
err_quit("usage: server7");
37 fd = Door_create(squareproc, NULL, 0);
38 unlink(PATH_SQUARE_DOOR);
39 Close(Open(PATH_SQUARE_DOOR, O_CREAT | O_RDWR, FILE_MODE));
40 Fattach(fd, PATH_SQUARE_DOOR);
41 fd = Door_create(sqrtproc, NULL, 0);
42 unlink(PATH_SQRT_DOOR);
43 Close(Open(PATH_SQRT_DOOR, O_CREAT | O_RDWR, FILE_MODE));
44 Fattach(fd, PATH_SQRT_DOOR);
45 for (;;)
46
pause();
47 }
- 10 ( ):

solaris % client7 77
result: 5929 8.77496

219

, , :

solaris % server7
squareproc: thread id 4, arg = 77
sqrtproc: thread id 4, arg = 77
,
.
DOOR_ UNREF
15.3 , door_create DOOR_UNREF. ,
, , , .
, ( ) DOOR_UNREF_DATA.
.
1. , door_create, . , ,
2 1, 1 0, ,
.
2. , , . fdetach,
fdetach, ( unlink rm).
3. , open, , close,
, . .
, fattach,
. 15.13 main.

15.13. ,

//doors/serverunref1.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

void
servproc(void *cookie, char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc)
{
long arg, result;
if (dataptr == DOOR_UNREF_DATA) {
printf("door unreferenced\n");
Door_return(NULL, 0, NULL, 0);
}
arg = *((long*)dataptr);
printf("thread id %ld, arg = %ld\n", pr_thread_id(NULL), arg);
sleep(6);
result = arg * arg;
Door_return((char *)&result, sizeof(result), NULL, 0);
}

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

int
main(int argc, char **argv)
{
int fd;
if (argc != 2)
err_quit("usage: server1 ");
/* */
fd = Door_create(servproc, NULL, DOOR_UNREF);
unlink(argv[1]);
Close(Open(argv[1], O_CREAT | O_RDWR, FILE_MODE));
Fattach(fd, argv[1]);
Close(fd);
/* servproc() */
for(;;)
pause();
}

7-10 .
door_return .
28 fattach. door_bind,
doo_info door_revoke.

220

, , :

solaris % serverunref1 /tmp/door1


door unreferenced
, , 1 door_create 2
fattach. close , .
, , .
:

solaris
result:
solaris
result:
.
15.14.

% clientunref1 /tmp/door1 11
121
% clientunref1 /tmp/door1 22
484

, .
- , close . main

15.14. ,

//doors/serverunref2.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

void
servproc(void *cookie. char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc)
{
long arg, result;
if (dataptr == DOOR_UNREF_DATA) {
printf("door unreferenced\n");
Door_return(NULL, 0, NULL, 0);
}
arg = *((long *)dataptr);
printf("thread id %ld, arg = %ld\n", pr_thread_id(NULL), arg);
sleep(6);
result = arg * arg;
printf("thread id %ld returning\n", pr_thread_id(NULL));
Door_return((char *)&result, sizeof(result), NULL, 0);
}

18
19
20
21
23
24
25
26
27
28
29
30
31
32
33

int
main(int argc, char **argv)
{
int fd;
if (argc != 2)
err_quit("usage: server1 ");
/* , */
fd = Door_create(servproc, NULL, DOOR_UNREF);
unlink(argv[1]);
Close(Open(argv[1], O_CREAT | O_RDWR, FILE_MODE));
Fattach(fd, argv[1]);
/* servproc() */
for(;;)
pause();
}

6- . ,
rm:

solaris % ls l /tmp/door2
Drw-r--r-- 1 rstevens other1 0 Apr 16 08:58 /tmp/door2
solaris % rm /tmp/door2
:

221

solaris % serverunref2 /trap/door2


door unreferenced
, : door_create,
fattach. rm , .
.
-. ,
. 15.14 15.2.

solaris
%
clientunref2
/tmp/door2
44
&
clientunref2
clientunref2/tmp/door2 55 &
[2] 13552
[3] 13553
[4] 13554
solaris % rm /tmp/door2
solaris % result: 1936
result: 3025
result: 4356

/tmp/door2

55

&

solaris % serverunref2 /tmp/door2


thread id 4, arg = 44
thread id 5, arg = 55
thread id 6, arg = 66
thread id 4 returning
thread id 5 returning
thread id 6 returning
door unreferenced
. 1 door_create, 2 fattach.
open, 2 5. 4.
4 1 (), 2 1 .
, DOOR_UNREF (
2 1), , .
15.8.
, :
fork;
exec.
, fork, ,
. .
Unix ,
.
.

Unix 14.7 [24]. Berkeley


. 18 [23]. SVR4 ,
I_SENDFD I_RECVFD ioctl. 15.5.1 [21]. SVR4
Unix.
, . . 4.7
( ) . 1 , 1 .
, ( ).
. ,
.
, , :

int fd;
fd = Open();
Write(pipefd, &fd, sizeof(int));
. . ,
4. , . ,
, fork.
4, open . 4 ,
7, , 7 ,
4 . 15.4 [21] 18.4 [23] , : (4 7
) . Unix
, .
desc_ptr door_arg_t
door_desc_t desc_num .
door_return door_desc_t
:

222

. 15.4. ,

typedef struct door_desc {


door_attr_t d_attributes; /* */
union {
struct { /* , tag = DOOR_DESCRIPTOR */
int d_descriptor; /* */
door_id_t d_id; /* */
} d_desc;
} d_data;
} door_desc_t;
(union), , .
( d_desc, ), (d_attributes)
DOOR_DESCRIPTOR.

, , ,
. . 15.4 . 15.15 .

15.15. ,

//doors/clientfd1.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5
int door, fd;
6
char argbuf[BUFFSIZE], resbuf[BUFFSIZE], buff[BUFFSIZE];
7
size_t len, n;
8
door_arg_t arg;
9
if (argc != 2)
10
err_quit("usage: clientfd1 ");
11 door = Open(argv[1], O_RDWR); /* */
12 Fgets(argbuf, BUFFSIZE, stdin); /* */
13 len = strlen(argbuf);
14 if (argbuf[len-1] == '\n')
15
len--;
16 /* */
17 arg.data_ptr = argbuf; /* - */
18 arg.data_size = len + 1; /* */
19 arg.desc_ptr = NULL;

223

20 arg.desc_num = 0;
21 arg.rbuf = resbuf; /* - */
22 arg.rsize = BUFFSIZE; /* */
23 Door_call(door, &arg); /* */
24 if (arg.data_size != 0)
25
err_quit("%.*s", arg.data_size, arg.data_ptr);
26 else if (arg.desc_ptr == NULL)
27
err_quit("desc_ptr is NULL");
28 else if (arg.desc_num != 1)
29
err_quit("desc_num = %d", arg.desc_num);
30 else if (arg.desc_ptr->d_attributes != DOOR_DESCRIPTOR)
31
err_quit("d_attributes = %d", arg.desc_ptr->d_attributes);
32 fd = arg.desc_ptr->d_data.d_desc.d_descriptor;
33 while((n = Read(fd, buff, BUFFSIZE)) > 0)
34
Write(STDOUT_FILENO, buff, n);
35 exit(0);
36 }

,
9-15 , , . , ,
, .

16-22 door_arg_t. , .


23-31 . . ,
( ) , . err_quit
.


32-34 door_desc_t, .
15.16 . main 15.3 .

15.16. ,

//doors/serverfd1.c
1 #include "unpipc.h"
2 void
3 servproc(void *cookie, char *dataptr, size_t datasize,
4
door_desc_t *descptr, size_t ndesc)
5 {
6
int fd;
7
char resbuf[BUFFSIZE];
8
door_desc_t desc;
9
dataptr[datasize-1] = 0; /* */
10 if ((fd = open(dataptr, O_RDONLY)) == 1) {
11
/* , */

224

12
snprintf(resbuf, BUFFSIZE, "%s: can't open, %s",
13
dataptr, strerror(errno));
14
Door_return(resbuf, strlen(resbuf), NULL, 0);
15 } else {
16
/* , */
17
desc.d_data.d_desc.d_descriptor = fd;
18
desc.d_attributes = DOOR_DESCRIPTOR;
19
Door_return(NULL, 0, &desc, 1);
20 }
21 }


9-14 open. ,
.


15-20 , .
/tmp/fd1, :

solaris % clientfd1 /tmp/fd1


/etc/shadow
/etc/shadow: can't open. Permission denied
solaris % clientfd1 /tmp/fd1
/no/such/file
/no/such/file: can't open. No such file or directory
solaris % clientfd1 /tmp/fd1
/etc/ntp.conf
multicastclient 224.0.1.1
driftfile /etc/ntp.drift
, .
, .

, . , printf
open. , . ,
. , , .
door_return, , door_return ! sendmsg
Unix ioctl SVR4,
sendmsg ioctl. -, door_return .
, ,
.
Solaris 2.7 DOOR RELEASE. d_attributes DOOR
DESCRIPTOR | DOOR_RELEASE, .
15.9. door server_create
15.6 ,
. (detached threads) ,
(thread cancellation) (scheduling class), ,
door_create. - ,
door_server_create :

#include
typedef void Door_create_proc(door_info_t *);
Door_create_proc *door_server_create(Door_create_proc *proc);
/* */
door_create 15.3, typedef .
( door_info_t)
(void). door_server_create ,
.
.
, , door_info_t,
. di_proc , di_data , .
. - 15.1. main. . 15.5
.

225

. 15.5. -

15.17 main .

15.17. main

//doors/server6.c
42 int
43 main(int argc, char **argv)
44 {
45 if (argc != 2)
46 err_quit("usage: server6 ");
47 Door_server_create(my_create);
48 /* */
49 Pthread_mutex_lock(&fdlock);
50 fd = Door_create(servproc, NULL, DOOR_PRIVATE);
51 Pthread_mutex_unlock(&fdlock);
52 unlink(argv[1]);
53 Close(Open(argv[1], O_CREAT | O_RDWR, FILE_MODE));
54 Fattach(fd, argv[1]);
55 /* servproc() */
56 for(;;)
57
pause();
58 }
15.2 :
1. fd ( , 15.18).
2. door_create ( 15.18).
3. door_server_create , (my_thread, ,
).
4. door_create () DOOR_PRIVATE 0. ,
, .
door_server_create DOOR_PRIVATE
. :
1. .
.
2. DOOR_PRIVATE, .
, , DOOR_PRIVATE , ,
DOOR_PRIVATE.
3. , .
, .

226

4. DOOR_PRIVATE .
. door_bind ,
.
15.18 : my_create ( ) my_thread (, ,
my_create).

15.18.
//doors/server6.c
13 pthread_mutex_t fdlock = PTHREAD_MUTEX_INITIALIZER;
14 static int fd = 1; /* */
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

void *
my_thread(void *arg)
{
int oldstate;
door_info_t *iptr = arg;
if ((Door_server_proc*)iptr->di_proc == servproc) {
Pthread_mutex_lock(&fdlock);
Pthread_mutex_unlock(&fdlock);
Pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
Door_bind(fd);
Door_return(NULL, 0, NULL, 0);
} else
err_quit("my_thread: unknown function: %p", arg);
return(NULL); /* */
}

30
31
32
33
34
35
36
37
38
39
40
41

void
my_create(door info_t *iptr)
{
pthread_t tid;
pthread_attr_t attr;
Pthread_attr_init(&attr);
Pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
Pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
Pthread_create(&tid, &attr, my_thread, (void *)iptr);
Pthread_attr_destroy(&attr);
printf("my_thread: created server thread %ld\n", pr_thread_id(&tid)):
}


30-41 my_create . pthread_create ,
PTHREAD_SCOPE_SYSTEM (detached). my_thread.
door_info_t.
, . ,
, , di_proc
door_info_t.

PTHREAD_SCOPE_SYSTEM ,
. PTHREAD_SCOPE_PROCESS;
. , , , ,
door_return. PTHREAD_SCOPE_PROCESS .
, , ,
, , pthread_join.

,
15-20 my_thread, pthread_create.
door_info_t, my_create. servproc, ,
.

227

21-22 door_create .
door_create. fd ,
door_create ( ). , my_thread ,
, fdlock : door_create
door_create ( fd ). my_thread
( , ),
. , , ,
.


23 pthread_create .
door_call ( 15.26), ,
. ( ) door_call,
( ), door_return . , ,
- (, ),
. ,
, .

, PTHREAD_SCOPE_SYSTEM .
. , ,
, .


24 door_bind , , door_bind .
, .


25 door_return
.
15.19. 15.6.

15.19.
//doors/server6.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12

void
servproc(void *cookie, char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc)
{
long arg, result;
arg = *((long *) dataptr);
printf("thread id %ld, arg = %ld\n", pr_thread_id(NULL), arg);
sleep(5);
result = arg * arg;
Door_return((char *)&result, sizeof(result), NULL, 0);
}

, :

solaris % server6 /tmp/door6


my_thread: created server thread 4
door_create , .
, . :

solaris
result:
solaris
result:

% client6 /tmp/door6 11
121
% client6 /tmp/door6 22
484

228

solaris % client6 /tmp/door6 33


result: 1089
, . ( 5),
4 . :

my_thread: created
thread id 4, arg =
thread id 4, arg =
thread id 4, arg =

server thread 5
11
22
33

solaris % client6 /tmp/door6 44 &client6 /tmp/door6 55 &client6 /tmp/door6 66 &


[2] 4919
[3] 4920
[4] 4921
solaris % result: 1936
result: 4356
result: 3025
, , ( 6 7) 4, 5 6
:

thread id 4, arg =
my_thread: created
thread id 5, arg =
my_thread: created
thread id 6, arg =

44
server thread 6
66
server thread 7
55

15.10. door_bind, door unbind door_revoke


, :

#include
int door_bind(int fd);
int door_unbind(void);
int door_revoke(int fd);
/* e 0 , 1 */
door_bind 15.18. ,
fd. - , .
door_unbind , .
door_revoke fd. , .
, , .
15.11.
, .
, , . (
. 15.1), , .
, .
, .

door_call, , -
- . , , pthread_exit.
( ). 15.20 .

15.20. ,

//doors/serverintr1.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11

void
servproc(void *cookie, char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc)
{
long arg, result;
pthread_exit(NULL); /* , */
arg = *((long*)dataptr);
result = arg * arg;
Door_return((char*)&result, sizeof(result), NULL, 0);
}

15.2, - 15.1.
, , door_call EINTR, :

229

solaris % clientintr1 /tmp/door1 11


door_call error: Interrupted system call
door_call
door_call , ( door_call
). , , 6
, 15.21.

15.21. 6

//doors/serverintr2.
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11

void
servproc(void *cookie, char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc)
{
long arg, result;
sleep(6); /* SIGCHLD */
arg = *((long*)dataptr);
result = arg * arg;
Door_return((char*)&result, sizeof(result), NULL, 0);
}

15.2: SIGCHLD,
2 . , 2 door_call ,
SIGCHLD , door_call. - 15.22.

15.22. ,
SIGCHLD
//doors/clientintr2.c
1 #include "unpipc.h"
2
3
4
5
6

void
sig_chld(int signo)
{
return; /* door_call() */
}

7 int
8 main(int argc, char **argv)
9 {
10 int fd;
11 long ival, oval;
12 door_arg_t arg;
13 if (argc != 3)
14
err_quit("usage: clientintr2 ");
15 fd = Open(argv[1], O_RDWR); /* */
16 /* */
17 ival = atol(argv[2]);
18 arg.data_ptr = (char*)&ival; /* */
19 arg.data_size = sizeof(long); /* */
20 arg.desc_ptr = NULL;
21 arg.desc_num = 0;
22 arg.rbuf = (char*)&oval; /* */
23 arg.rsize = sizeof(long); /* */
24 Signal(SIGCHLD, sig_chld);

230

25 if (Fork() == 0) {
26
sleep(2); /* */
27
exit(0); /* SIGCHLD */
28 }
29 /* */
30 Door_call(fd, &arg);
31 printf(result: %ld\n", oval);
32 exit(0);
33 }
, EINTR:

solaris % clientintr2 /tmp/door2 22


door_call error: interrupted system call
, door_call.

, EINTR , , -
(SIGCHLD)? ,
.
, , 6
. 15.23 .

15.23. ,

//doors/serverintr3.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13

void
servproc(void *cookie, char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc)
{
long arg, result:
printf("thread id %ld called\n", pr_thread_id(NULL));
sleep(6); /* SIGCHLD */
arg = *((long*)dataptr);
result = arg * arg;
printf("thread id %ld returning\n", pr_thread_id(NULL));
Door_return((char *) &result, sizeof(result), NULL, 0);
}

15.24 -.

15.24. , door_call
, EINTR
//doors/clientintr3.c
1 #include "unpipc.h"
2 volatile sig_atomic_t caught_sigchld;
3
4
5
6
7
8

void
sig_chld(int signo)
{
caught_sigchld = 1;
return; /* door_call() */
}

9 int
10 main(int argc, char **argv)
11 {

231

12 int fd, rc;


13 long ival, oval;
14 door_arg_t arg;
15 if (argc != 3)
16
err_quit("usage: clientintr3 ");
17 fd = Open(argv[1], O_RDWR); /* */
18 /* */
19 ival = atol(argv[2]);
20 arg.data_ptr = (char*)&ival; /* */
21 arg.data_size = sizeof(long); /* */
22 arg.desc_ptr = NULL;
23 arg.desc_num = 0;
24 arg.rbuf = (char*)&oval; /* */
25 arg.rsize = sizeof(long); /* */
26 Signal(SIGCHLD, sig_chld);
27 if (Fork() == 0) {
28
sleep(2); /* */
29
exit(0); /* SIGCHLD */
30 }
31 /* : */
32 for (;;) {
33
printf("calling door_call\n");
34
if ((rc = door_call(fd, &arg)) == 0)
35
break; /* */
36
if (errno == EINTR && caught_sigchld) {
37
caught_sigchld = 0;
38
continue; /* door_call */
39
}
40
err_sys("door_call error");
41 }
42 printf("result: %ld\n", oval);
43 exit(0);
44 }
2-8 caught_sigchld, SIGCHLD.
31-42 door_call , .
, , :

solaris
calling
calling
result:

% clientintr3 /tmp/door3 33
door_call
door_call
1089

door_call , 2 caught_sigchld
1. door_call EINTR door_call . .
, , :

solaris %
thread id
thread id
thread id
thread id

serverintr3 /tmp/door3
4 called
4 returning
5 called
5 returning

door_call, , .
, . , .
,
. , , : ,
. , .
( ), .
. , .

, . poaa-e
15.25.

15.25. ,
door_call
232

//doors/clientintr4.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

int
main(int argc, char **argv)
{
int fd;
long ival, oval;
door_arg_t arg;
if (argc != 3)
err_quit("usage: clientintr4 ");
fd = Open(argv[1], O_RDWR); /* */
/* */
ival = atol(argv[2]);
arg.data_ptr = (char*)&ival; /* */
arg.data_size = sizeof(long); /* */
arg.desc_ptr = NULL;
arg.desc_num = 0;
arg.rbuf = (char*)&oval; /* */
arg.rsize = sizeof(long); /* */
/* */
alarm(3);
Door_call(fd, &arg);
printf("result: %ld\n", oval);
exit(0);
}

20 alarm(3) door_call. SIGALRM


, , , . door_call,
.
15.26 .

15.26. ,

//doors/serverintr4.
1 #include "unpipc.h"
2 void
3 servproc_cleanup(void *arg)
4 {
5
printf("servproc cancelled, thread id %ld\n", pr_thread_id(NULL));
6 }
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

void
servproc(void *cookie, char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc)
{
int oldstate, junk;
long arg, result;
Pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
pthread_cleanup_push(servproc_cleanup, NULL);
sleep(6);
arg = *((long*)dataptr);
result = arg * arg;
pthread_cleanup_pop(0);
Pthread_setcancelstate(oldstate, &junk);
Door_return((char*)&result, sizeof(result), NULL, 0);
}

233

, 8.5 15.18.
, , , :
, ( door_return),
;
, , .
pthread_setcancelstate ,
. oldstate,
. pthread_cleanup_push servproc_cleanup.
,
( . .). .
6- , door_call.
, Alarm clock SIGALRM:

solaris % clientintr4 /tmp/door4 44


Alarm Clock
solaris % clientintr4 /tmp/door4 44
Alarm Clock
, .
:

solaris % serverintr4 /tmp/door4


servproc canceled, thread id 4
servproc canceled, thread id 5
, - , , 4
( 5) .
15.12.
.
.
. door_create
, fattach . open
door_call . door_return.
open.
( ). ( IPC)
( ).
.
. ,
Unix (, XTI, ).
.
EINTR.
. .

1. door_call ?
2. fstat 15.3? , .
3. Solaris 2.6 sleep() , .
15.6?
4. 15.3 , door_create FD_CLOEXEC.
fcntl door_create . , , exec,
?
5. 15.23 15.24 printf . .
?
6. , fd 15.17 15.18, , .
?
7. , ?
8. , door_revoke . ,
door_ll .
9. 15.17 , ,
. , , . , fd
main.
10. 15.18 pthread_attr_init pthread_attr_ destroy , .
?
16
Sun RPC
16.1.
, :
1. , .
2. , .
, :
2.1. , , IPC ,
2.2. , - .
. 15.1. 1, 2.1, 2.2.
2.1, IPC, ,
, , .
.
,
. XTI, [24].
socket, connect, read write, socket, bind, listen, accept, read write.
(, Web, Telnet) .
.
(remote procedure call RPC). , ,
. ,
, , . ,

234

, . RPC
.

RPC 15.1 15.2 Sun RPC .


long, . 16.1[1] , square..

16.1. RPC
//sunrpc/square1/square.x
1 struct square_in { /* () */
2 long arg1;
3 };
4 struct square_out { /* () */
5 long res1;
6 };
7 program SQUARE_PROG {
8 version SQUARE_VERS {
9
square_out SQUAREPROC(square_in) = 1; /* = 1 */
10 } = 1; /* */
11 } = 0x31230000; /* */
. RPC. , .


1-6 ( long) ( long).

,
7-11 RPC SQUARE_PROG, (SQUARE_VERS),
SQUAREPROC. square_in,
square_out. 1, , 32- . (
. 16.1.)
rpcgen, Sun RPC.
main , . 16.2.

16.2. main ,

//sunrpc/square1/client.c
1 #include "unpipc.h" /* */
2 #include "square.h" /* rpcgen */
3 int
4 main(int argc, char **argv)
5 {
6
CLIENT *cl;
7
square_in in;
8
square_out *outp;
9
if (argc != 3)
10
err_quit("usage: client ");
11 cl = Clnt_create(argv[1], SQUARE_PROG, SQUARE_VERS, "tcp");
12 in.arg1 = atol(argv[2]);
13 if ((outp = squareproc_1(&in, cl)) == NULL)
14
err_quit("ls", clnt_sperror(cl, argv[1]));
15 printf("result: %ld\n", outp->res1);
16 exit(0);

235

17 }

,
rpcgen
2 square.h, rpcgen.


6 (client handle) cl. FILE (
CLIENT ).


11 clnt_create, RPC:

#include
CLIENT *clnt_create(const char *host, unsigned long prognum, unsigned long
versnum, const char *protocol);
/* . NULL
*/
FILE, , . ,
, . clnt_create , RPC
.
clnt_create IP- , . ,
. (square., 16.1). , TCP
UDP.


12-15 , (&in), .
- . RPC
. , .
, RPC.
square.x SQUAREPROC, squareproc_1.
.
. main rpcgen.
16.3.

16.3. ,
Sun RPC
//sunrpc/square1/server.c
1 #include "unpipc.h"
2 #include "square.h"
3
4
5
6
7
8
9

square_out *
squareproc_l_svc(square_in *inp, struct svc_req *rqstp)
{
static square_out out;
out.res1 = inp->arg1 * inp->arg1;
return(&out);
}


3-4 , _svc. ANSI
square.x, , 16.2 ( ),
( ).

236

, ,
RPC , ( ).


6-8 . ,
. , . (static).

, .
16.2, .
Solaris, BSD/OS, , :

solaris
result:
solaris
result:

% client bsdi 11
121
% client 209.75.135.35 22
484

, IP-. , IP clnt_create.
, clnt_create, , ,
-:

solaris % client nosuchhost 11


nosuchhost: RPC: Unknown host RPC
clnt_create error
-
solaris % client localhost 11
localhost: rpc: program not registered
clnt_create error
.
, . XTI Solaris, BSD/OS
- RPC . RPC
.
, Sparc Solaris Intel x86 BSD/OS
. Sparc big endian ([2]), Intel little endian () (
3.4 [24]). RPC XDR (
), 16.8.
- - , .
:

solaris
solaris
solaris
solaris
solaris

%
%
%
%
%

rpcgen-square.x
cc-client.-client.
cc-square_clnt.c-square_clnt.o
cc-square_xdr.-square_xdr.o
cc-client client.square_clnt.o square_xdr.o libunpipc.a lnsl

rpcgen ANSI square.h. rpcgen


(client stub) square_clnt. square_xdr.,
XDR. ( , ) libunpipc.a, lnsl
Solaris ( RPC XDR ).
, rpcgen . square_svc.c main
, square_xdr., , :

solaris % cc server. server.


solaris % c square_svc.c square_svc.o
solaris % cc server server. square_svc.o libunpipc.a lnsl
, Solaris.
( , Solaris, BSD/OS),
. , ( NFS), ,
, (, square_xdr.o), .

237

. 16.1. - RPC
. 16.1 -. ,
. , square.h.
. 16.2 . :
1. , , -. clnt_create.
. clnt_create
TCP ( TCP 16.2).
16.3.
2. , . 16.2 squareproc_1, ,
, rpcgen square_clnt.c. ,
. ,
. (marshaling).
RPC (clnt_create ). Solaris
lnsl, BSD/OS .
3. . (, write
sendto).
4. . TCP UDP.
5. . .
6. ( squareproc_l_svc
16.3), , .
7. , .
8.
.
9. .
10. ( read recvfrom).
11. .
.

. 16.2. ,

, RPC [26]. [4], (White) Xerox RPC.


1981 Courier. RPC [2].
RPC Cedar, Dorado Xerox 80-. Xerox RPC

238

, , ! Courier Unix BSD


4.x, RPC .
Sun RPC 1985. (Bob Lyon), Sun Xerox 1983.
ONC/RPC: Open Network Computing Remote Procedure Call ( ),
Sun RPC. Courier. Sun RPC
TCP UDP. RPCSRC. 90-
TLI ( XTI), [24]. ,
. ftp://playground.sun.com/pub/rpc, , ,
rpcsrc, , TLI, tirpcsrc ( TI-RCP Transport Independent -
).
RFC 1831 [18] Sun RPC RPC, . RFC 1832 [19]
XDR , . RFC 1833 [20] :
RPCBIND , (port mapper).
, Sun RPC, Sun (NFS).
RPC, (rpcgen ).
. , NFS,
Sun RPC.
80- Apollo Sun RPC, Sun RPC.
NCA (Network Computing Architecture ). RPC NCA/RPC,
XDR NDR (Network Data Representation ).
NIDL (Network Interface Definition Language ) . 16.1.
NCK (Network Computing Kernel).
Apollo Hewlett-Packard 1989, NCA OSF's DCE (Distributed Computing Environment
), RPC. DCE http://www.camp.opengroup.org/tech/dce.
DCE RPC ftp://gatekeeper.dec.com/pub/DEC/DCE. DCE RPC
171 . DCE .

Sun RPC , DCE RPC, ,


Unix. DCE RPC ( ).
, Linux. Sun RPC. RPC
Courier, Sun DCE , RPC .
Unix RPC. , Sun
http://docs.sun.com, Developer Collection 280- ONC+ Developer's Guide.
Digital Unix http:// www.unix.digital.com/faqs/publications/pub_page/V40D_DOCS.HTM 116-
Programming with ONC RPC.
RPC .
http://www.kohala.com/~rstevens/papers.others/rpc.comments.txt.
TI-RPC ( RPC) TCP
UDP, TI-RPC , .
16.2.
15.6, , .
. , Sun RPC .
. 16.4 , , 5 , .

16.4. 5-

//sunrpc/square2/server.c
1 #include "unpipc.h"
2 #include "square.h"
3
4
5
6
7
8
9
10
11
12
13

square_out *
squareproc_1_svc(square_in *inp, struct svc_req *rqstp)
{
static square_out out;
printf("thread %ld started, arg = %ld\n",
pr_thread_id(NULL), inp->arg1);
sleep(5);
out.res1 = inp->arg1 * inp->arg1;
printf("thread %ld done\n", pr_thread_id(NULL));
return(&out);
}

, -:

solaris % client localhost 22 & client localhost 33& client localhost 44 &
[3] 25179
[4] 25180
[5] 25181
solaris % result: 484 5
result: 1936
5
result: 1089
5

239

, 5 . ,
, , : ,
:

solaris % server
thread 1 started, arg = 22
thread 1 done
thread 1 started, arg = 44
thread 1 done
thread 1 started, arg = 33
thread 1 done
. .

15 , .
printf . Sun RPC , 12.4
[24]. syslog . DDEBUG
,

#define DEBUG

( square_svc.c, rpcgen). main


, . printf .
Solaris 2.4 rpcgen.
, rpcgen, . , ,
. rpcgen.
, ,
static 16.3. , square., 1 2.
.
16.5 -.

16.5. main

//sunrpc/square3/client.c
1 #include "unpipc.h"
2 #include "square.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

int
main(int argc, char **argv)
{
CLIENT *cl;
square_in in;
square_out out;
if (argc != 3)
err_quit("usage: client ");
cl = Clnt_create(argv[1], SQUARE_PROG, SQUARE_VERS, "tcp");
in.arg1 = atol(argv[2]);
if (squareproc_2(&in, &out, cl) != RPC_SUCCESS)
err_quit("%s", clnt_sperror(cl, argv[1]));
printf("result: %ld\n", out.res1);
exit(0);
}


8 square_out, .


12-14 squareproc_2 out, .
( 16.2) RPC_SUCCESS,
. enumclnt_stat .
16.6 . 16.4, , 5
, .

240

16.6.
//sunrpc/square3/server.c
1 #include "unpipc.h"
2 #include "square.h"
3
4
5
6
7
8
9
10
11
12

bool_t
squareproc_2_svc(square_in *inp, square_out *outp, struct svc_req *rqstp)
{
printf("thread %Id started, arg = %ld\n",
pr_thread_id(NULL), inp->arg1);
sleep(5);
outp->res1 = inp->arg1 * inp->arg1;
printf("thread %ld done\n", pr_thread_id(NULL));
return(TRUE);
}

13
14
15
16
17
18
19

int
square_prog_2_freeresult(SVCXPRT *transp, xdrproc_t xdr_result,
caddr_t result)
{
xdr_free(xdr_result, result);
return(1);
}


3-12 .
( 16.3) .
svc_req . TRUE,
FALSE.

, XDR
13-19 , .
.
xdr_free ( 16.19 16.10).
(, ), .
- - :

solaris % client localhost 55 & client localhost 66 & client localhost 77 &
[3] 25427
[4] 25428
[5] 25429
solaris % result: 4356
result: 3025
result: 5929
, , . , ,
:

solaris % server
thread 1 started, arg = 55
thread 4 started, arg = 77
thread 6 started, arg = 66
thread 6 done
thread 1 done
thread 4 done

, , ,
. , Digital Unix 4.0B BSD/OS 3.1 RPC, . ,
, #ifdef
. , BSD/OS, , Solaris, ,
, , .

241

16.3.
16.5 , :
. , RPC
port mapper ( ). TCP 111 UDP 111,
Sun RPC. RPC ,
. , ,
. ,
.

, 2049.
,
NFS, . NFS
.
Solaris 2.x Sun RPCBIND. ,
, TI-RPC , TCP UDP.
(port mapper). ,
TCP UDP.
:
1. poaa .
portmap rpcbind.
2. main, , rpcgen, svc_create.
, , (, ) ,
TCP UDP. poao
TCP UDP .
RPC, RPC (
111). , poao , RFC 1833 [20].
RPC: TCP UDP, 3 4 ,
RPCBIND.
poa RPC, poa- , poay rpcinfo.
, , 111 :

solaris % rpcinfo p
program vers proto port service
100000 4 tcp 111 rpcbind
100000 3 tcp 111 rpcbind
100000 2 tcp 111 rpcbind
100000 4 udp 111 rpcbind
100000 3 udp 111 rpcbind
100000 2 udp 111 rpcbind
( .) , Solaris 2.6 ,
111, TCP, UDP. poa RPC /etc/rpc.
BSD/OS 3.1, , :

bsdi % rpcinfo p
program vers proto port
100000 2 tcp 111 portmapper
100000 2 udp 111 portmapper
Digital Unix 4.0 :

alpha % rpcinfo p
program vers proto port
100000 2 tcp 111 portmapper
100000 2 udp 111 portmapper
, . TCP aa UDP UDP. rpcinfo 16.3, :

solaris % rpcinfo p
program vers proto port service
8243773444 1 udp
8243773444 1 tcp
824377344 0x31230000 ( poa, 16.1).
1. , TCP UDP ,
( clnt_create 16.2).
3. clnt_create. ( 16.2) IP- , poa,
, . RPC poae (
UDP), .
RPC .
16.1 0x31230000. 32- poa , .
16.1.

16.1. Sun RPC

0x000000000x1fffffff Sun
0x200000000x3fffffff
0x400000000x5fffffff ( , )
242

0x600000000xffffffff
poaa rpcinf , . poaax RPC
. /usr/inciude/rpcsvc.
Inetd RPC
, rpcgen, inetd. 12.5 [24].
, rpcgen, , main ,
XTI, , , inetd.
RPC, inetd, /etc/inetd.conf.
: RPC, , .
Solaris:

rstatd/2-4
rpc.rstatd

tli

rpc/datagram_v

wait

root

/usr/lib/netsvc/rstat/rpc.rstatd

poa ( /etc/rpc); 2, 3 4.
XTI ( ), , eaa.
/etc/netconfig, , : UDP /dev/clts. 29 [24] XTI.
(wait) inetd
XTI. RPC wait /etc/inetd.conf.
, root, , poaa.
poa poa ( poa ).
inetd XTI poa .
rpcinfo:

solaris % rpcinfo | grep statd


100001 2 udp
0.0.0.0.128.11
100001 3 udp
0.0.0.0.128.11
100001 4 udp
0.0.0.0.128.11
100001 2 ticlts \000\000\020.
100001 3 ticlts \000\000\020.
100001 4 ticlts \000\000\020.

rstatd
rstatd
rstatd
rstatd
rstatd
rstatd

superuser
superuser
superuser
superuser
superuser
superuser

XTI, 128256+11 = 32779, ,


UDP.
UDP 32779, inetd fork, exec
/usr/lib/netsvc/rstat/rpc.rstatd. fork exec XTI 0, 1 2,
inetd (. 12.7 [24]). inetd XTI,
, ( inetd) . wait.
, rpcgen. XTI,
, RPC. RPC svc_tli_create svc_reg,
. ( ) ,
. svc_run .
, inetd, , inetd
. RPC, rpcgen,
( 2 ). .
fork exec . ,
inetd SIGCHLD, XTI.
16.4.
RPC . , , .
, AUTH_NONE.
Unix, AUTH_SYS. RPC
( , , ,
) . 16.2 ,
Unix. 16.7 -.

16.7. ,
unix
//sunrpc/square4/client.
1 #include "unpipc.h"
2 #include "square.h"
3 int
4 main(int argc, char **argv)
5 {
6
CLIENT *cl;
7
square_in in;
8
square_out out;
9
if (argc != 3)
10
err_quit("usage: client ");
11 cl = Clnt_create(argv[1], SQUARE_PROG, SQUARE_VERS, "tcp");
12 auth_destroy(cl->cl_auth);
13 cl->cl_auth = authsys_create_default();

243

14 in.arg1 = atol(argv[2]);
15 if (squareproc_2(&in, &out, cl) != RPC_SUCCESS)
16
err_quit("%s", clnt_sperror(cl, argv[1]));
17 printf("result: %ld\n", out.resl);
18 exit(0);
19 }
12-13 . auth_destroy
, ( , ).
authsys_create_default Unix cl_auth CLIENT.
16.5.
16.8 , 16.6.
square_prog_2_freeresult, .

16.8. ,
Unix
//sunrpc/square4/server.c
1 #include "unpipc.h"
2 #include "square.h"
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

bool_t
squareproc_2_svc(square_in *inp, square_out *outp, struct svc_req *rqstp)
{
printf("thread %Id started, arg = %ld, auth = %d\n",
pr_thread_id(NULL), inp->arg1, rqstp->rq_cred.oa_flavor);
if (rqstp->rq_cred.oa_flavor == AUTH_SYS) {
struct authsys_parms *au;
au = (struct authsys_parms *)rqstp->rq_clntcred;
printf("AUTH_SYS: host %s, uid %ld, gid %ld\n",
au->aup_machname, (long) au->aup_uid, (long) au->aup_gid);
}
sleep(5);
outp->res1 = inp->arg1 * inp->arg1;
printf("thread %ld done\n", pr_thread_id(NULL));
return(TRUE);
}

6-8 svc_req, :

struct svc_req {
u_long rq_prog; /* */
u_long rq_vers; /* */
u_long rq_proc; /* */
struct opaque_auth rq_cred:/* */
caddr_t rq_clntcred; /* ( ) */
SVCXPRT *rq_xprt; /* */
};
struct opaque_auth {
enum_t oa_flavor; /* flavor: AUTH_xxx */
caddr_t oa_base; /* */
u_int oa_length; /* MAX_AUTH_BYTES */
};
rq_cred , oa_flavor , .
, , oa_base.
, , rq_clntcred, ,
. -9_12 , AUTH_SYS.
Unix (rq_clntcred) authsys_parms, :

struct authsys_parms {
u_long aup_time; /* */
char *aup_machname; /* */
uid_t aup_uid; /* */

244

gid_t aup_gid; /* */
u_int aup_len; /* aup_gids[] */
gid_t *aup_gidsl; /* */
};
, EUID EGID.
, :

solaris % server
thread 1 started, arg = 44, auth = 1
AUTH_SYS: host solaris.kohala.com, uid 765, gid 870
thread 1 done
Unix , . RPC,
Unix, , .
, , .

- NFS Unix, NFS


( 2.7 [24]). NFS , , .
, ,
. , ,
NFS . ,
, , ,
NFS.
RPC , , :
(credentials, verifier). (, . .).
(, , . .), .
: , , , , . (, ,
), , .
, . Unix
, , . , ,
, .
AUTH_SHORT Unix, verifier .
, Unix, .
.
AUTH_DES DES Data Encryption Standard ( ).
. RPC (secure RPC),
NFS, NFS .
AUTH_KERB Kerberos MIT.
19 [5] , .
16.5. -
- , Sun RPC. -:
1. - . TCP UDP.
2. - UDP , .
TCP - , .
, TCP . ,
. , .
, . ( ,
, ) RPC.
, RPC, RPC. RPC
. , .
clnt_control .
fcntl getsockopt setsockopt :

#include
bool_t clnt_control(CLIENT *cl, unsigned int request, char *ptr);
/* TRUE , FALSE */
cl , ptr request.
- 16.2, , -. 16.9
-.

16.9. ,
RPC
//sunrpc/square5/client.c
1 #include "unpipc.h"
2 #include "square.h"
3
4
5
6
7
8

int
main(int argc, char **argv)
{
CLIENT *cl;
square_in in;
square_out *outp;

245

9
struct timeval tv;
10 if (argc != 4)
11
err_quit("usage: client ");
12 cl = Clnt_create(argv[1], SQUARE_PROG, SQUARE_VERS, argv[3]);
13 Clnt_control(cl, CLGET_TIMEOUT, (char*)&tv);
14 printf("timeout = %ld sec, %ld usec\n", tv.tv_sec, tv.tv_usec);
15 if (clnt_control(cl, CLGET_RETRY_TIMEOUT, (char *) &tv) == TRUE)
16
printf("retry timeout = %ld sec, %ld usec\n", tv.tv_sec, tv.tv_usec);
17 in.arg1 = atol(argv[2]);
18 if ((outp = squareproc_1(&in, cl)) == NULL)
19
err_quit("%s", clnt_sperror(cl, argv[1]));
20 printf(result: %ld\n", outp->res1);
21 exit(0);
22 }



10-12 , clnt_create, .

-
13-14 clnt_control , , .
CLGET_TIMEOUT; - timeval, .
.

-
15-16 CLGET_RETRY_TIMEOUT. - ,
UDP. , FALSE, .
-, 1000 5, -
. bsdi, , TCP, UDP.
, :

solaris % date ; client bsdi 44 tcp ; date


Wed Apr 22 14:46:57 MST 1998
timeout = 30 sec, 0 usec
- 30
bsdi: RPC: Timed out
Wed Apr 22 14:47:22 MST 1998
25
solaris % date ; client bsdi 55 udp ; date
Wed Apr 22 14:48:05 MST 1998
timeout = 1 sec, 1 usec
-
retry timeout = 15 sec, 0 usec
bsdi: RPC: Timed out
Wed Apr 22 14:48:31 MST 1998
25
TCP -, clnt_control, 30 , 25 .
UDP - 1.
, , squareproc_1 square_clnt.c, rpcgen.
clnt_call, timeval TIMEOUT,
, 25 . clnt_call - 30 TCP 1 UDP.
, - clnt_control CLSET_TIMEOUT.
-, clnt_control, .

- UDP tcpdump.
, , 15 .
TCP
tcpdump , TCP, ,
( TCP),
. 25 FIN, ,
TCP. 2.5 [24] .
, Sun RPC TCP : TCP clnt_create
, . TCP clnt_destroy
:

#include
void clnt_destroy(CLIENT *cl);

246

16.2 , , clnt_destroy pause. 16.10


-.

16.10.
TCP
//sunrpc/square9/client.c
1 #include "unpipc.h" /* */
2 #include "square.h" /* rpcgen */
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int
main(int argc, char **argv)
{
CLIENT, *cl;
square_in in;
square_out *outp;
if (argc != 3)
err_quit("usage: client ");
cl = Clnt_create(argv[1], SQUARE_PROG, SQUARE_VERS, "tcp");
in.arg1 = atol(argv[2]);
if ((outp = squareproc_1(&in, cl)) == NULL)
err_quit("%s", clnt_sperror(c1, argv[1]));
printf("result: %ld\n", outp->res1);
in.arg1 *= 2;
if ((outp = squareproc_1(&in, cl)) == NULL)
err_quit("%s", clnt_sperror(cl, argv[1]));
printf("result: %ld\n", outp->res1);
clnt_destroy(cl);
pause();
exit(0);
}

solaris % client kalae 5


result: 25
result: 100
,
tcpdump. ,
TCP ( clnt_create) . clnt_destroy,
.

- (transaction ID XID)
. RPC, 32-
RPC. .
. :
1. , XID XID . , . TCP,
, UDP
XID .
2. , , , XID.
.
TI-RPC XID . . ^
XOR ( ):

struct timeval now;


gettimeofday(&now, NULL);
xid = getpid() ^ now.tv_sec ^ now.tv_usec;

RPC svc_dg_enablecache.
, :

#include
int svc_dg_enablecache(SVCXPRT *xprt, unsigned long size);
/* 1 . 0 */
xprt , svc_req ( 16.4).
. .
, size .
:

247

;
;
;
XID;
(IP- + UDP).
RPC .
.
,
. , . - ,
, . ,
, (, UDP), TCP
TCP (. 16.6).
16.6.
15.24 , door_call
. , , .
: , , ,
.
:
1. , .
.
2. , .
, , . , ,
.
3. , , , .
, .
, , .
, .
, , . .
TCP , , .
( ), , .
,
RPC.
UDP , , ,
, .
UDP , , .
, TCP.
:
TCP,
UDP ,
UDP
:
TCP, ;
, (
, . .);
TCP UDP , TCP
, , UDP, , TCP (., , 20.5 [24]);
UDP ;
UDP .
TCP.
16.7.
, TCP.
UDP , .
-, , , ,
, . , TCP,
FIN [24, . 36-37], , RPC .

, . -
tcp clnt_call 16.2 , 16.9.
abort. - FIN ,
tcpdump.
Solaris , BSD/OS:

solaris % client bsdi 22 tcp


bsdi: RPC: Unable to receive; An event requires attention
FIN RPC .
squareproc_1. (RPC_CANTRECV) , clnt_sperror ( -
Clnt_create) Unable to receive. (An event requires attention) XTI,
, clnt_sperror. 30
RPC_xxx. .
, , RPC (RPC_CANTRECV),
:

bsdi % client solaris 11 tcp


solaris: RPC: Unable to receive; errno = Connection reset by peer
Solaris , abort, .
, , .
, abort pthread_exit, poae 15.20. BSD/OS,
Solaris:

bsdi % client solaris 33 tcp


solaris: RPC: Timed out

248

TCP . ,
FIN. -. , , ,
.

, TCP, RPC, FIN. ,
. ( 15.11 ,
.)
, alarm(3) ,
sl (6). 15.25 15.26. SIGALRM,
3 . BSD/OS, Solaris:

bsdi % client solaris 44 tcp


Alarm call
, . . 6-
. tcpdump, :
( 3 ) FIN, .
TCP half-close ( , 18.5 [22]);
6 , TCP. TCP
FIN, TCP , [24, . 130-132].
RST, . , .
.
UDP RPC . , , : , ,
. .
RPC, TCP, ,
. , , , ,
. , TCP .
-.
16.8. XDR:
.
, . RPC ,
. ( long 32
, 64). , (big-endian little-endian, [24, . 66-69 137-140].
, 16.3. little-endian 86, big-endian Sparc,
( ).
Sun RPC XDR (External Data Representation ) (RFC 1832
[19]). XDR . XDR (implicit typing),
. , 32- ,
.

OSI. ASN.1 (Abstract Syntax Notation one), BER


(Basic Encoding Rules). , .
: , , , , single,
, , .
XDR , . big-endian.
, IEEE. 3
, , . , 5- SII
12 :
4- , 5;
5- ;
3 0 ().
XDR .
1. RPC ( .)?
.
2. rpcgen ?
3. ?
16.2 . RPC
XDR . rpcgen, .

16.2. , xdr rpcgen

RPC (.x)
1 const name = value
2 typedef declaration;
3 char var; short var; int var; long var; hyper var;
4
5
6
7
8
9

(.h)
#define name value
typedef declaration;
char var; short var; int var; long var;
longlong_t var;
unsigned char var; unsigned short var; unsigned u_char var; u_short var; u_int var; u_long var;
int var; unsigned long var; unsigned hyper var;
u_longlong_t var;
float var; double var; quadruple var;
float var; double var; quadruple var;
bool var;
bool_t var;
enum var {name = const, }
enum var {name = const, }; typedef enum
var var;
opaque var[n];
char var[n];
opaque var;
struct { u_int var_len; char *var_val; } val;
249

10
11
12
13

string var
datatype var[n];
datatype var
struct var {members };

char *var;
datatype var[n];
struct { uint var_len; datatype *var_val; } var;
struct var {members }; typedef struct var
var;
14 union var switch (int disc) { case discvalueA:
struct var { int disc; union { armdeclA;
armdeclA; case discvalueB: amrdeclB; default: armdeclB; defaultdecl; } var_u; }; typedef
defaultdecl; };
struct var var;
15 datatype *name;
datatype *name;
.
1. const #define.
2. typedef typedef.
3. . XDR 32- ( ), 64-.

64- long long int long long. ,


. longlong_t,
:

typedef long long longlong_t;

XDR 32 , 64- Unix 64 (, LP64,


[24, . 27]). XDR . ,
- int8_t, int16_t . .
4. . 4 32- , 64-.
5. . 32- , 64-, 128-.

(quadruple precision) long double. He


. long double, double.
quadruple,

typedef long double quadruple;

Solaris 2.6, ,

%#include

RPC, . #include
rpcgen .
6. boolean . RPC TRUE 1, a FALSE 0.
7. (enumeration) enum . rpcgen
.
8. 8- .
9. ,
. (,
RPC) , .
, , .
10. ASCII-. ,
, , ( ).
strlen.
, .
11. n .
12. , ,
. . ,
, m.
13. . rpcgen (typedef).
14. (), .
. 16.2 , int, unsigned int, enum, bool ( 32 ). 32- , ,
. default void, .
.
15. , 16.24. XDR
, .
. 16.3 XDR.

250

. 16.3. XDR
: XDR RPC
XDR RPC. XDR -
, .
- . 16.11 data .,
XDR, RPC.

(.) XDR. RPC , RPC (RPCL) XDR


, . RPCL .

16.11. XDR
//sunrpc/xdr1/data.x
1 enum result_t {
2
RESULT_INT = 1, RESULT_DOUBLE = 2
3 };
4
5
6

union union_arg switch (result_t result) {


case RESULT_INT:
int intval;

251

7 case RESULT_DOUBLE:
8
double doubleval;
9 default:
10 void;
11 };
12 struct data {
13 short short_arg;
14 long long_arg;
15 string vstring_arg<128>; /* */
16 opaque fopaque_arg[3]; /* */
17 opaque vopaque_arg<>; /* */
18 short fshort_arg[4]; /* */
19 long vlong_arg<>; /* */
20 union_arg uarg;
21 };

1-11 , .
RESULT_INT, .
RESULT_DOUBLE, . .


12-21 , , XDR.
RPC, rpcgen .
data.h data_xdr., XDR, , data..
16.12 rpcgen data.h. ,
(. 16.2).

16.12. data.h,
rpcgen data.x
//sunrpc/xdr1/data.h
1 /*
2
* Please do not edit this file. It was generated using rpcgen.
3
*/
4 #ifndef _DATA_H_RPCGEN
5 #define _DATA_H_RPCGEN
6

#include

7 enum result_t {
8
RESULT_INT = 1,
9
RESULT_DOUBLE = 2
10 };
11 typedef enum result_t result_t;
12 struct union_arg {
13 result_t result;
14 union {
15
int intVal;
16
double doubleval;
17 } union_arg_u;

252

18 };
19 typedef struct union_arg union_arg;
20 struct data {
21 short short_arg;
22 long long_arg;
23 char *vstring_arg;
24 char fopaque_arg[3];
25 struct {
26
u_int vopaque_arg_len;
27
char *vopaque_arg_val;
28 } vopaque_arg;
29 short fshort_arg[4];
30 struct {
31
u_int vlong_arg_len;
32
long *vlong_arg_val;
33 } vlong_arg;
34 union_arg uarg;
35 };
36 typedef struct data data:
37
38
39
40

/* 4the xdr functions */


extern bool_t xdr_result_t(XDR *, result_t*);
extern bool_t xdr_union_arg(XDR *, union_arg*);
extern bool_t xdr_data(XDR *, data*);

41 #endif /* !_DATA_H_RPCGEN */
data_xdr. xdr_data, data, .
_data 16.11. , , write..
data, xdr_data XDR
.
16.13.

16.13.
XDR
//sunrpc/xdr1/write.c
1 #include "unpipc.h"
2 #include "data.h"
3 int
4 main(int argc, char **argv)
5 {
6
XDR xhandle;
7
data out; /* , */
8
char *buff; /* XOR */
9
char vop[2];
10 long vlong[3];
11 u_int size;
12 out.short_arg = 1;
13 out.long_arg = 2;
14 out.vstring_arg = "hello, world"; /* */
15 out.fopaque_arg[0] = 99; /* */
16 out.fopaque_arg[1] = 88;
17 out.fopaque_arg[2] = 77;
18 vop[0] = 33; /* */
19 vop[1] = 44;
20 out.vopaque_arg.vopaque_arg_len = 2;

253

21 out.vopaque_arg.vopaque_arg_val = vop;
22 out.fshort_arg[0] = 9999; /* */
23 out.fshort_arg[1] = 8888;
24 out.fshort_arg[2] = 7777;
25 out.fshort_arg[3] = 6666;
26 vlong[0] = 123456; /* */
27 vlong[l] = 234567;
28 vlong[2] = 345678;
29 out.vlong_arg.vlong_arg_len = 3;
30 out.vlong_arg.vlong_arg_val = vlong;
31 out.uarg.result = RESULT_INT; /* */
32 out.uarg.union_arg_u.intval = 123;
33 buff = Malloc(BUFFSIZE); /* 4- */
34 xdrmem_create(&xhandle, buff, BUFFSIZE, XDR_ENCODE);
35 if (xdr_data(&xhandle, &out) != TRUE)
36
err_quit("xdr_data error");
37 size = xdr_getpos(&xhandle);
38 Write(STDOUT_FILENO, buff, size);
39 exit(0);
40 }

12-32 . .
RESULT_INT 123.


33 malloc , XDR .
. char .

XDR
34 xdrmem_create , buff,
XDR . XDR xhandle .
XDR ( , . .).
XDR_ENCODE, XDR XDR.


35-36 xdr_data, rpcgen data_xdr.c, out XDR.
TRUE .



37-38 xdr_getpos XDR ( ,
). .
16.14 read, , ,
data.

16.14. data
XDR
//sunrpc/xdr1/read.c

254

1
2

#include "unpipc.h"
#include "data.h"

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

int
main(int argc, char **argv)
{
XDR xhandle;
int i;
char *buff;
data in;
ssize_t n;
buff = Malloc(BUFFSIZE); /* 4- */
n = Read(STDIN_FILENO, buff, BUFFSIZE);
printf("read %ld bytes\n", (long) n);
xdrmem_create(&xhandle, buff, n, XDR_DECODE);
memset(&in, 0, sizeof(in));
if (xdr_data(&xhandle, &in) != TRUE)
err_quit("xdr_data error");
printf("short_arg = %d, long_arg = %ld, vstring_arg = '%s'\n",
in.short_arg, in.long_arg, in.vstring_arg);
printf("fopaque[] = %d, %d, %d\n",
in.fopaque_arg[0], in.fopaque_arg[1], in.fopaque_arg[2]);
printf("vopaque<> =");
for (i = 0; i < in.vopaque_arg.vopaque_arg_len; i++)
printf(" %d", in.vopaque_arg.vopaque_arg_val[i]);
printf("\n");
printf("fshort_arg[] = %d, %d, %d, %d\n", in.fshort_arg[0],
in.fshort_arg[1], in.fshort_arg[2], in.fshort_arg[3]);
printf("vlong<> =");
for (i = 0; i < in.vlong_arg.vlong_arg_len; i++)
printf(" %ld", in.vlong_arg.vlong_arg_val[i]);
printf("\n");
switch (in.uarg.result) {
case RESULT_INT:
printf("uarg (int) = %d\n", in.uarg.union_arg_u.intval);
break;
case RESULT_DOUBLE:
printf("uarg (double) = %g\n", in.uarg.union_arg_u.doubleval);
break;
default:
printf("uarg (void)\n");
break;
}
xdr_free(xdr_data, (char*)&in);
exit(0);
}


11-13 malloc . , .

XDR, ,

14-17 XDR, XDR_DECODE, , XDR .


i n xdr_data buff .
, XDR (, xdr_string) . xdr_data
, 16.13. xdrmem_create:

255

XDR_ENCODE, XDR_DECODE. XDR (xhandle) xdrmem_create


XDR .


18-42 data.

XDR
43 xdr_free (. 16.10).
write Sparc, data:

solaris % write > data


solaris % ls -l data
-rw-rw-r-- 1 rstevens other1 76 Apr 23 12:32 data
, 72 . 16.4, .
BSD/OS Digital Unix, , :

bsdi % read < data


read 76 bytes
short_arg = 1, long_arg = 2, vstring_arg = 'hello, world'
fopaque[] =99, 88, 77
vopaque<> = 33 44
fshort_arg[] = 9999, 8888, 7777, 6666
vlong<> = 123456 234567 345678
uarg (int) = 123
alpha % read < data
read 76 bytes
short_arg = 1, long_arg = 2, vstring_arg = 'hello, world'
fopaque[] = 99, 88, 77
vopaque<> = 33 44
fshort_arg[] = 9999, 8888, 7777, 6666
vlong<> = 123456 234567 345678
uarg (int) = 123

. 16.4. XDR, 16.13


:
BUFFSIZE ( unpi.h .1), .
, , XDR .
sizeof , XDR . ,
, XDR . 16.15 .

16.15. XDR

256

//sunrpc/xdrl/exampl.
1 const MAXC = 4;
2 struct example {
3 short a;
4 double b;
5 short c[MAXC];
6 };
, 16.16, , XDR .
28 .

16.16. ,
XDR
//sunrpc/xdr1/example.c
1 #include "unpipc.h"
2 #include "example.h"
3
4
5
6
7
8
9
10
11
12

int
main(int argc, char **argv)
{
int size;
example foo;
size = RNDUP(sizeof(foo.a)) + RNDUP(sizeof(foo.b)) +
RNDUP(sizeof(foo.c[0])) * MAXC;
printf("size = %d\n", size);
exit(0);
}

8-9 RNDUP . BYTES_PER_XDR_UNIT (4).


, .
. stringd<10>,
RNDUP(sizeof( int)) ( ) RNDUP(sizeof(char)*10) ( ). ,
(, float e<>). , ,
XDR ( 16.5).
:
XDR, 16.17.

16.17. XDR,

//sunrpc/xdr1/opt1.x
1 union optlong switch (bool flag) {
2 case TRUE:
3
long val;
4 case FALSE:
5
void;
6 };
7 struct args {
8
optlong arg1; /* */
9
long arg2<1>; /* */
10 long *arg3; /* */
11 };

257

1-8 FALSE TRUE . TRUE, long;


. XDR :
4 1 (TRUE) 4
4 0 (FALSE).


9 , :
4 1 4
4 0.

XDR
10 . :
4 1 4
4 0
. ,
. , . ,
.
, , , TRUE
1, , .
16.18 , rpcgen .

16.18. ,
16.17
//sunrpc/xdr1/opt1.h
7 struct optlong {
8
bool_t flag;
9
union {
10 long val;
11 } optlong_u;
12 };
13 typedef struct optlong optlong;
14 struct args {
15 optlong arg1;
16 struct {
17
u_int arg2_len;
18
long *arg2_val;
19 } arg2;
20 long *arg3;
21 };
22 typedef struct args args;
14-21 , .
16.19 poa, , long .

16.19.

//sunrpc/xdr1/opt1z.
1 #include "unpipc.h"
2 #include "opt1.h"
3
4
5
6

int
main(int argc, char **argv)
{
int i;

258

7
XDR xhandle;
8
char *buff;
9
long *lptr;
10 args out;
11 size_t size;
12 out.arg1.flag = FALSE;
13 out.arg2.arg2_len = 0;
14 out.arg3 = NULL;
15 buff = Malloc(BUFFSIZE); /* */
16 xdrmem_create(&xhandle, buff, BUFFSIZE, XOR_ENCODE);
17 if (xdr_args(&xhandle, &out) != TRUE)
18
err_quit("xdr_args error");
19 size = xdr_getpos(&xhandle);
20 lptr = (long*)buff;
21 for (i = 0; i < size; i += 4)
22
printf("%ld\n", (long) ntohl(*lptr++));
23 exit(0);
24 }


12-14 FALSE, 0,
(NULL).


15-19 out XDR.

XDR
20-22 XDR 4 , ntohl (host-to-network long integer) XDR
big-endian . , XDR :

solaris % opt1z
0
0
0
, 4 , , .
16.20 , , XDR
.

16.20.
16.17
//sunrpc/xdr1/opt1.c
1 #include "unpipc.h"
2 #include "opt1.h"
3 int
4 main(int argc, char **argv)
5 {
6
int i;
7
XOR xhandle;
8
char *buff;
9
long lval2, lval3, *lptr;
10 args out;
11 size_t size;
12 out.arg1.flag = TRUE;

259

13 out.arg1.optlong_u.val = 5;
14 lval2 = 9876;
15 out.arg2.arg2_len = 1;
16 out.arg2.arg2_val = &lval2;
17 lval3 = 123;
18 out.arg3 = &lval3;
19 buff = Malloc(BUFFSIZE); /* 4 */
20 xdrmem_create(&xhandle, buff, BUFFSIZE, XDR_ENCODE);
21 if (xdr_args(&xhandle, &out) != TRUE)
22
err_quit("xdr_args error");
23 size = xdr_getpos(&xhandle);
24 lptr = (long *) buff;
25 for (i = 0; i < size; i += 4)
26
printf("%ld\n", (long) ntohl(*lptr++));
27 exit(0);
28 }


12-18 TRUE, long.
1. .
4- :

solaris % opt1
1 TRUE
5
1
9876
1
123
:
, XDR
, . -.
XDR 16.21.

16.21. XDR
-
//sunrpc/xdr1/opt2.x
1 struct mylist {
2 string name<>;
3 long value;
4 mylist *next;
5 };
6 struct args {
7 mylist *list;
8 };
1-5 mylist - .
.
16.22 , rpcgen opt2..

16.22. ,
rpcgen
//sunrpc/xdr1/opt2.h
7 struct mylist {
8
char *name;

260

9
long value;
10 struct mylist *next;
11 };
12 typedef struct mylist mylist;
13 struct args {
14 mylist *list;
15 };
16 typedef struct args args;
16.23 , -
XDR.

16.23. ,

1
2
3

//sunrpc/xdr1/opt2.c
#include "unpipc.h"
#include "opt2.h"

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

int
main(int argc, char **argv)
{
int i;
XDR xhandle;
long *lptr;
args out; /* , */
char *buff; /* */
mylist nameval[4]; /* */
size_t size;
out.list = &nameval[2]; /* [2] > [1] > [0] */
nameval[2].name = "name1";
nameval[2].value = 0x1111;
nameval[2].next = &nameval[1];
nameval[1].name = "namee2";
nameval[1].value = 0x2222;
nameval[1].next = &nameval[0];
nameval[0].name = "nameee3";
nameval[0].value = 0x3333;
nameval[0].next = NULL;
buff = Malloc(BUFFSIZE); /* 4 */
xdrmem_create(&xhandle, buff, BUFFSIZE, XDR_ENCODE);
if (xdr_args(&xhandle, tout) != TRUE)
err_quit("xdr_args error");
size = xdr_getpos(&xhandle);
lptr = (long*)buff;
for (i = 0; i < size; i += 4)
printf("%8lx\n", (long)ntohl(*lptr++));
exit(0);
}


11-22 , . nameval[2], nameval[1] nameval[0].
(out.list) &nameval[2]. , , XDR
, , ,
. , .
, 1 4 (
TRUE). 4 , 0. :

261

solaris % opt2
1

5

6e616d65 (name)
31000000 1
1111

1

6

6e616d65
65320000 2 2
2222

1

7

6e616d65
65653300 3 1
3333

0

XDR ,
.
16.9. RPC
. 16.5 RPC TCP.
TCP ,
. Sun RPC , . 4 : , 31 ( ).
0, .

4- big-endian, 4- XDR, XDR,


.
TCP UDP, UDP (XID), . 16.7.

TCP RPC ,
, 31- . UDP ( )
, 65507 ( IPv4). , TI-RPC,
8192 , 8000 , TCP.

262

. 16.5. RPC TCP


XDR RPC, RFC 1831. . 16.5 :

enum autn_flavor {
AUTH_NONE = 0,
AUTH_SYS = 1,
AUTH_SHORT = 2
/* and more to be defined */
};
struct opaque_auth {
auth_flavor flavor;
opaque body<400>;
};
enum msg_type {
CALL = 0,
REPLY = 1
};
struct call_body {

263

unsigned int rpcvers; /* RPC: 2 */


unsigned int prog; /* */
unsigned int vers; /* */
unsigned int proc; /* */
opaque_auth cred; /* */
opaque_auth verf; /* */
/* , */
};
struct rpc_msg {
unsigned int xid;
union switch (msg_type mtype) {
case CALL:
call_body cbody;
case REPLY:
reply_body rbody;
} body;
};
, ,
. , , 0. Unix
:

struct authsys_parms {
unsigned int stamp;
string machinename<255>;
unsigned int uid;
unsigned int gid;
unsigned int gids<16>;
};
AUTH_SYS, AUTH_NONE. RPC , ,
. . 16.6 . . 16.7 RPC
. UDP.
XDR RPC, RFC 1831.

enum reply_stat {
MSG_ACCEPTED = 0,
MSG_DENIED = 1
};
enum accept_stat {
SUCCESS = 0, /* RPC */
PROG_UNAVAIL = 1, /* */
PROG_MISMATCH = 2, /* */
PROC_UNAVAIL = 3, /* */
GARBAGE_ARGS = 4, /* */
SYSTEM_ERR = 5 /* . . */
};
struct accepted_reply {
opaque_auth verf;
union switch (accept_stat stat) {
case SUCCESS:
opaque results[0]; /* , */
case PROG_MISMATCH:
struct {
unsigned int low; /* */
unsigned int high; /* */
} mismatch_info;
default: /* PROG_UNAVAIL, PROC_UNAVAIL, GARBAGE_ARGS, SYSTEM_ERR */
void;
} reply_data;
};
union reply_body switch (reply_stat stat) {
case MSG_ACCEPTED:
accepted_reply areply;
case MSG_DENIED:

264

rejected_reply rreply;
} reply;

. 16.6. RPC

, RPC :

enum reject_stat {
RPC_MISMATCH = 0, /* RPC 2 */
AUTH_ERROR =1 /* */
};
enum auth_stat {
AUTH_OK = 0, /* */
/* */
AUTH_BADCRED = 1, /* (
) */
AUTH_REJECTEDCRED = 2, /* */
AUTH_BADVERF = 3, /* ( ) */
AUTH_REJECTEDVERF = 4, /* */
AUTH_TOOWEAK = 5, /* */
/* */
AUTH_INVALIDRESP = 6, /* */
AUTH_FAILED = 7 /* */
};
union rejected_reply switch (reject_stat stat) {
case RPC_MISMATCH:
struct {
unsigned int low; /* RPC */
unsigned int high; /* RPC */
} mismatch_info;
case AUTH_ERROR:
auth_stat stat;
};

265

. 16.7. UDP
16.10.
Sun RPC , ,
. , , RPC,
. main , ,
. , ,
RPC.
rpcgen , RPC.
, , XDR, .
XDR . XDR ,
- , , , . . , XDR RPC
- . (, XTI, ,
- ).
Sun RPC . 32- , 32-
32- . RPC (RPCBIND).
RPC TCP UDP , ,
. RPC , RPC,
, TCP UDP.
RPC RPC .
- XTI. Sun RPC
: Unix ( , ), DES (
) Kerberos.
- RPC RPC ( ).
, , TCP, RPC -,
. , UDP,
RPC - -. RPC
.
, .
, RPC .
.
Sun RPC , . , ,
. rpcgen . Sun
RPC , , , ,
. RPC 164, :
11 auth_ ();
26 clnt_ ();
5 pmap_ ( );
24 rpc_ ( );
44 svc_ ();
54 xdr_ ( XDR).
, XTI 25 , , Posix System V,
10 . 15 Posix, 10
. 11 - Posix fcntl.

1. . , ,
? , ?

266

2. RPC UDP, . , 20
. 15 , .
?
3. XDR string . , char [10] string
s<10>?
4. string 16.11 128 10 write. ?
data_xdr. , , . ?
5. xdrmem_create ( ) 16.13 50 , .
6. 16.5 UDP. , TCP
. TCP? (: TCP ,
?)
7. , . ,
?
8. tcpdump 16.5, TCP, , 48
, 32 ( TCP IPv4). 16.3. UDP TCP?
9. RPC , , , ?
, 16.2?
10. read 16.19 , , vstring_arg.
, vstring_arg? , .
11. Sun RPC 0 ( 1,
16.1). , , rpcgen, ( ,
, ). .
. ,
, . clnt_call
.
12. .1 65536 Sun RPC UDP? 16384 32768
. .2 Sun RPC UDP?
13. , xdr_free 16.19 .

for(;;) {
xdrmem_create xdr_free.
ps. xdr_free.
.

V).

(IPC):
1. ( , Posix System V).
2. ( , -, , Posix System

3. (, Posix System V).


4. ( Solaris, Sun RPC).
, . , ,
. ,
IPC.
16 : IPC - ?
, . IPC Unix , -
, ( ). , , IPC
.
, IPC .
1. . , IPC ,
. , ,
IPC, .
2. ( . 1.3). Unix
Posix. 1998 IPC System V ( ,
), Posix. Posix IPC, , ,
Unix 98. Posix (
) . , Posix,
. -, Unix 98,
Posix, - .
, Unix- ( /dev/zero, MAP_ANON).
Sun RPC Unix, Solaris.
3. . IPC, .
, , IPC
.
4. . ,
Posix ( , , ).
, , ,
. System V .
IPC, :
a . Posix System V
. : TCP , a UDP
.
Posix , .
System V .
select poll ( 6 [24]), 5.12 6.9.
(FIFO). Posix System V
. Posix .
System V .
Posix System V
. ( XTI UDP
18 19 [24]).
, - .
. ,

267

. Posix : .
( Posix IPC), .
System V ( key_t),
.
fcntl , . System V
. , , - Posix
.
fcntl ( ) , .
- .
Posix System V . , , -
.
Posix . System V
.
Oae System V IPC ,
( 3.8). Oae Posix IPC .
System V IPC ( , , . .)
XXXctl IPC_STAT poao ipcs. Posix .
, stat ls,
Posix IPC . ,
.
, , -, ,
(. 5.1): sem_post fcntl.
, Posix System V
: read write ( ).
( 15.5). 5.4
, : BSD/OS ( 14.8 [24])
SVR4, ( 15.3.1 [21]).


.1.
:
(pipes);
(FIFO);
Posix;
System V;
;
SunRPC.
, :
;
-;
fcntl;
Posix;
System V.
IPC,
.
:
1. (bandwidth) IPC.
( ) . (, write read
), , .
2. (latency) , , IPC
. 1 .
, IPC, IPC
. , .
.
, , .
, .

, IPC, lmbench [15].


, ( . .), IPC.
http://www.bitmover.com/lmbench.
, , , . ,
. IPC,
. , ,
.
.2.
, . .
: SparcStation 4/110 Solaris 2.6 Digital Alpha (DEC 3000 model 300, Pelican)
Digital Unix 4.0. /etc/system Solaris 2.6 :

set msgsys:msginfo_msgmax = 16384


set msgsys:msginfo_msgmnb = 32768
set msgsys:msginfo_msgseg = 4096
16384 System V (. .2).
Digital Unix 4.0B sysconfig:

ipc:
msg-max = 16384
msg-mnb = 32768

. .2 Sparc Solaris 2.6, . .1 .

268

, . System V
, , ( 3.8),
16384 .
4096 Solaris 2.6, , .
[24] TCP Unix.
lmbench 65536 . TCP .

. .1 Solaris 2.6 Digital Unix 4.0B.
.1. 1 ( )

Solaris 324
2.6
DUnix 574
4.0B

Sun Sun

RPC RPC TCP
UDP

Posix
System V
TCP UDP
584
260
121
1891 1677 798
755
465
995

625

1648 1373 848

639

289

. .1. Solaris 2.6.


A.4 , ,
lmbench. TCP UDP .
.2. Solaris 2.6 (/)

Posix
1024
6,3
3,7
2048
8,7
5,3
4096
9,8
8,4
8192
12,7
10,2
16384
13,1
11,6
32768
13,2
13,4
65536
13,7
14,4

System V
4,9
6,3
6,6
5,8
6,1

Sun
RPC
TCP
6,3
0,5
10,0
0,9
12,6
1,6
14,4
2,4
16,8
3,2
11,4
3,5
12,2
3,7

Sun
RPC TCP

UDP
0,5
1,0
2,8
2,8
3,4
4,3
13,2
11,3

269

. .2. (Digital Unix 4.0B)

.. Digital Unix 4.0B (/)

1024
2048
4096
8192
16384
32768
65536

9,9
15,2
17,1
16,5
17,3
15,9
14,2

Posix
1,8
3,5
5,9
8,6
11,7
14,0
9,4

System V
12,7
15,0
21,1
17,1
17,3

Sun
RPC
TCP
0,6
0,8
1,3
1,8
2,3
2,6
2,8

Sun
RPC
UDP
0,6
1,0
1,8
2,5

TCP

4,6

18,0


. .4 ,
Solaris 2.6, . .3 . 1000000 ,
1 5. . .5 Digital Unix 4.0, . .4 .

. .. (Solaris 2.6)

270

, . ,
. fcntl ,
, .
Digital Unix 4.0B Posix , ,
- . .

, .
, . ,
, , , .

..4. (Digital Unix 4.0B)


.4. Solaris 2.6 ( )

-
- Posix

fcn

Posix

Posix
System System
tl

V
V
UNDO
1
0,7
2,0
4,5
15,4
16,3
21,1
89,4
2
1,5
5,4
9,0
31,1
31,5
37,5
3
2,2
7,5
14,4
46,5
48,3
57,7
4
2,9
13,7
18,2
62,5
65,8
75,8
5
3,7
19,7
22,8
76,8
81,8
90,0
.5. Digital Unix 4.0B ( )

-
- Posix

Posix

Posix
System System
fcntl

V
V
UNDO
1
2,9
12,9
13,2
14,2
26,6
46,6
96,4
2
11,4
40,8
742,5
771,6
54,9
93,9
3
28,4
73,2
1080,5
1074,5
84,5
141,9
4
49,3
95,0
1534,1
1502,2
109,9
188,4
5
67,3
126,3
1923,3
1764,1
137,3
233,6

. .4 .5 . ,
. . .6 . .5
Solaris 2.6, . .7 . .6 Digital Unix 4.0B. , Solaris 2.6

271

. fcntl, .
7.2, Digital Unix 4.0B PTHREAD_PROCESS_SHARED,
. Posix Digital Unix 4.0B .

. .5. (Solaris 2.6)

. .6.
.6. Solaris 2.6 ( )

-
- Posix

Posix

Posix
System System
fcntl

V
V
UNDO
1
0,8
1,6
13,6
14,3
17,3
22,1
90,7
2
1,6
3,9
29,2
29,2
34,9
41,6
244,5
3
2,3
6,4
41,6
42,9
54,0
60,1
376,4
4
3,1
12,2
57,3
58,8
72,4
81,9
558,0
5
4,0
20,4
70,4
73,5
87,8
102,6
764,0
.7. Digital Unix 4.0B ( )

272

1
2
3
4
5

Posix

12,8
664,8
1236,1
1772,9
2179,9

Posix
12,5
659,2
1269,8
1804,1
2196,8

System V
30,1
58,6
96,4
120,3
147,7

System V
UNDO
49,0
95,7
146,2
197,0
250,9

fcntl
98,1
477,1
1785,2
2582,8
3419,2

.. :
, , Posix System V.
. .2 ..

. .7 .

. .7.

.1 bw_pipe, .

.1. main,

//bench/bw_pipe.c
1 #include "unpipc.h"
2 void reader(int, int, int);
3 void writer(int, int);
4 void *buf;
5 int totalnbytes, xfersize;
6 int
7 main(int argc, char **argv)
8 {
9
int i, nLoop, contpipe[2], datapipe[2];
10 pid_t childpid;
11 if (argc != 4)
12
err_quit("usage: bw_pipe <#loops> <#mbytes> <#bytes/write>");
13 nloop = atoi(argv[1]);
14 totalnbytes = atoi(argv[2]) * 1024 * 1024;
15 xfersize = atoi(argv[3]);
16 buf = Valloc(xfersize);
17 Touch(buf, xfersize);

273

18 Pipe(contpipe);
19 Pipe(datapipe);
20 if ((childpid = Fork()) == 0) {
21
writer(contpipe[0], datapipe[1]); /* child */
22
exit(0);
23 }
24 /* 4parent */
25 Start_time();
26 for (i = 0; i < nloop; i++)
27
reader(contpipe[1], datapipe[0], totalnbytes);
28 printf("bandwidth: %.3f MB/sec\n",
29
totalnbytes / Stop_time() * nloop);
30 kill(childpid, SIGTERM);
31 exit(0);
32 }


11-15 ( 5), ( 10,
1010241024 ) read write ( 1024 65536 ).

16-17 valloc malloc, . touch ( .3) 1


, . .

valloc Posix.1 Unix 98. /Open,


. Valloc malloc, valloc .


18-19 : contpipe[0] contpipe[1] , a datapipe[0] datapipe[1]
.

fork
20-31 , writer, reader. reader
nl . start_time , a stop_time .
.. , , ,
(stop_time , start_time). SIGTERM
. .2. reader writer.

.2. reader writer


//bench/bw_pipe.cvoid
33 void
34 writer(int contfd, int datafd)
35 {
36 int ntowrite;
37 for(;;) {
38
Read(contfd, &ntowrite, sizeof(ntowrite));
39
while (ntowrite > 0) {
40
Write(datafd, buf, xfersize);
41
ntowrite = xfersize;
42
}
43 }
44 }

274

45
46
47
48
49
50
51
52
53
54

void
reader(int contfd, int datafd, int nbytes)
{
ssize_t n;
Write(contfd, &nbytes, sizeof(nbytes));
while ((nbytes > 0) &&
((n = Read(datafd, buf, xfersize)) > 0)) {
nbytes = n;
}
}

writer
33-44 writer , .
, . ,
. , . write xfersize
.

reader
45-54 . ,
. read
, .
start_time, stop_time touch ..

.. start_sime, stop_time touch


//lib/timing.
1 #include "unpipc.h"
2 static struct timeval tv_start, tv_stop;
3
4
5
6
7

int
start_time(void)
{
return(gettimeofday(&tv_start, NULL));
}

8
9
10
11
12
13
14
15
16
17

double
stop_time(void)
{
double clockus;
if (gettimeofday(&tv_stop, NULL) == 1)
return(0.0);
tv_sub(&tv_stop, &tv_start);
clockus = tv_stop.tv_sec * 1000000.0 + tv_stop.tv_usec;
return(clockus);
}

18
19
20
21
22
23
24
25
26

int
touch(void *vptr, int nbytes)
{
char *cptr;
static int pagesize = 0;
if (pagesize == 0) {
errno = 0;
#ifdef _SC_PAGESIZE
if ((pagesize = sysconf(_SC_PAGESIZE)) == 1)

275

27
return(-1);
28 #else
29
pagesize = getpagesize(); /* BSD */
30 #endif
31 }
32 cptr = vptr;
33 while (nbytes > 0) {
34
*cptr = 1;
35
cptr += pagesize;
36
nbytes = pagesize;
37 }
38 return(0);
39 }
tv_sub .4. timeval, .

.4. tv_sub:
timeval
//lib/tv_sub.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10

void
tv_sub(struct timeval *out, struct timeval *in)
{
if ((out->tv_usec = in->tv_usec) < 0) { /* out = in */
--out->tv_sec;
out->tv_usec += 1000000;
}
out->tv_sec = in->tv_sec;
}

Sparc Solaris 2.6 :

solaris % bw_pipe
bandwidth: 13.722
solaris % bw_pipe
bandwidth: 13.781
solaris % bw_pipe
bandwidth: 13.685
solaris % bw_pipe
bandwidth: 13.665
solaris % bw_pipe
bandwidth: 13.584

5 10 65536
MB/sec
5 10 65536
MB/sec
5 10 65536
MB/sec
5 10 65536
MB/sec
5 10 65536
MB/sec

, 10 65536 write read. 13,7


, . .2.
Posix
.5 main , Posix. .6 reader
writer. , .

, .
4. IPC , ,
mq_send, . ,
. 4 8 Solaris 2.6 , . .2, Digital Unix 4.0B
12%. , ,
. ,
, .

.5. main
Posix
//bench/bw_pxmsg.c
1 #include "unpipc.h"

276

2
3
4
5
6

#define NAME "bw_pxmsg"


void reader(int, mqd_t, int);
void writer(int, mqd_t);
void *buf;
int totalnbytes, xfersize;

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

int
main(int argc, char **argv)
{
int i, nloop, contpipe[2];
mqd_t mq;
pid_t childpid;
struct mq_attr attr;
if (argc != 4)
err_quit("usage: bw_pxmsg <#loops> <#mbytes> <#bytes/write>");
nloop = atoi(argv[1]);
totalnbytes = atoi(argv[2]) * 1024 * 1024;
xfersize = atoi(argv[3]);
buf = Valloc(xfersize);
Touch(buf, xfersize);
Pipe(contpipe);
mq_unlink(Px_ipc_name(NAME)); /* error OK */
attr.mq_maxmsg = 4;
attr.mq_msgsize = xfersize;
mq = Mq_open(Px_ipc_name(NAME), O_RDWR | O_CREAT, FILE_MODE, &attr);
if ((childpid = Fork()) == 0) {
writer(contpipe[0], mq); /* child */
exit(0);
}
/* 4parent */
Start_time();
for (i = 0; i < nloop; i++)
reader(contpipe[1], mq, totalnbytes);
printf("bandwidth: %.3f MB/sec\n",
totalnbytes / Stop_time() * nloop);
kill(childpid, SIGTERM);
Mq_close(mq);
Mq_unlink(Px_ipc_name(NAME));
exit(0);
}

.6. reader writer


//bench/bw_pxmsg.c
41 void
42 writer(int contfd, mqd_t mqsend)
43 {
44 int ntowrite;
45 for(;;) {
46
Read(contfd, &ntowrite, sizeof(ntowrite));
47
while (ntowrite > 0) {
48
Mq_send(mqsend, buf, xfersize, 0);
49
ntowrite = xfersize;
50
}
51 }
52 }

277

53
54
55
56
57
58
59
60
61
62

void
reader(int contfd, mqd_t mqrecv, int nbytes)
{
ssize_t n;
Write(contfd, &nbytes, sizeof(nbytes));
while ((nbytes > 0) &&
((n = Mq_receive(mqrecv, buf, xfersize, NULL)) > 0)) {
nbytes = n;
}
}

System V
.7 main, System V, .8 reader
writer.

.7. main
System V
//bench/bw_svmsg.c
1 #include "unpipc.h"
2 void reader(int, int, int);
3 void writer(int, int);
4 struct msgbuf *buf;
5 int totalnbytes, xfersize;
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

int
main(int argc, char **argv)
{
int i, nloop, contpipe[2], msqid;
pid_t childpid;
if (argc != 4)
err_quit("usage: bw_svmsg <#loops> <#mbytes> <#bytes/write>");
nloop = atoi(argv[1]);
totalnbytes = atoi(argv[2]) * 1024 * 1024;
xfersize = atoi(argv[3]);
buf = Valloc(xfersize);
Touch(buf, xfersize);
buf->mtype = 1;
Pipe(contpipe);
msqid = Msgget(IPC_PRIVATE, IPC_CREAT | SVMSG_MODE);
if ((childpid = Fork()) == 0) {
writer(contpipe[0], msqid); /* */
exit(0);
}
Start_time();
for (i = 0; i < nloop; i++)
reader(contpipe[1], msqid, totalnbytes);
printf("bandwidth: %.3f MB/sec\n",
totalnbytes / Stop_time() * nloop);
kill(childpid, SIGTERM);
Msgctl(msqid, IPC_RMID, NULL);
exit(0);
}

.8. reader writer


//bench/bw_svmsg.c
34 void

278

35 writer(int contfd, int msqid)


36 {
37 int ntowrite;
38 for (;;) {
39
Read(contfd, &ntowrite, sizeof(ntowrite));
40
while (ntowrite > 0) {
41
Msgsnd(msqid, buf, xfersize sizeof(long), 0);
42
ntowrite = xfersize;
43
}
44 }
45 }
46
47
48
49
50
51
52
53
54
55

void
reader(int contfd, int msqid, int nbytes)
{
ssize_t n;
Write(contfd, &nbytes, sizeof(nbytes));
while ((nbytes > 0) &&
((n = Msgrcv(msqid, buf, xfersize sizeof(long), 0, 0)) > 0)) {
nbytes = n + sizeof(long);
}
}


, , fork .
, .
, . .7 reader . server,
. . .8 .

. .8.
Solaris, , ( 4.4).
. ,
Posix, , , . -
, . , ,
8 8 , ,
8 , N N/4 . :
door_call , . N
N/2 . RPC.
, . .1 , 25 .
.9 main . writer, server reader .10.

279

.9. main

//bench/bw_door.c
1 #include "unpipc.h"
2 void reader(int, int);
3 void writer(int);
4 void server(void *, char *, size_t, door_desc_t *, size_t);
5 void *buf;
6 int totalnbytes, xfersize, contpipe[2];
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

int
main(int argc, char **argv)
{
int i, nloop, doorfd;
char c;
pid_t childpid;
ssize_t n;
if (argc != 5)
err_quit("usage: bw_door <#loops> <#mbytes> <#bytes/write>");
nloop = atoi(argv[2]);
totalnbytes = atoi(argv[3]) * 1024 * 1024;
xfersize = atoi(argv[4]);
buf = Valloc(xfersize);
Touch(buf, xfersize);
unlink(argv[1]);
Close(Open(argv[1], O_CREAT | O_EXCL | O_RDWR, FILE_MODE));
Pipe(contpipe); /* SVR4 */
if ((childpid = Fork()) == 0) {
/* = */
if ((n = Read(contpipe[0], &c, 1)) != 1)
err_quit("child: pipe read returned %d", n);
doorfd = Open(argv[1], O_RDWR);
writer(doorfd);
exit(0);
}
/* = */
doorfd = Door_create(server, NULL, 0);
Fattach(doorfd, argv[1]);
Write(contpipe[1], &c, 1); /* */
Start_time();
for (i = 0; i < nloop; i++)
reader(doorfd, totalnbytes);
printf("bandwidth: %.3f MB/sec\n",
totalnbytes / Stop_time() * nloop);
kill(childpid, SIGTERM);
unlink(argv[1]);
exit(0);
}

A.10. writer, server, reader



//bench/bw_door.c
45 void

280

46 writer(int doorfd)
47 {
48 int ntowrite;
49 door_arg_t arg;
50 arg.desc_ptr = NULL; /* */
51 arg.desc_num = 0;
52 arg.rbuf = NULL; /* */
53 arg.rsize = 0;
54 for(;;) {
55
Read(contpipe[0], &ntowrite, sizeof(ntowrite));
56
while (ntowrite > 0) {
57
arg.data_ptr = buf;
58
arg.data_size = xfersize;
59
Door_call(doorfd, &arg);
60
ntowrite = xfersize;
61
}
62 }
63 }
64 static int ntoread, nread;
65
66
67
68
69
70
71
72
73
74

void
server(void *cookie, char *argp, size_t arg_size,
door_desc_t *dp, size_t n_descriptors)
{
char c;
nread += arg_size;
if (nread >= ntoread)
Write(contpipe[0], &c, 1); /* */
Door_return(NULL, 0, NULL, 0);
}

75
76
77
78
79
80
81
82
83
84
85

void
reader(int doorfd, int nbytes)
{
char c;
ssize_t n;
ntoread = nbytes; /* */
nread = 0;
Write(contpipe[1], &nbytes, sizeof(nbytes));
if ((n = Read(contpipe[1], &c, 1)) != 1)
err_quit("reader: pipe read returned %d", n);
}

Sun RPC
Sun RPC , , (. ).
( ), rpcgen. .11
RPC. , .
.12 -, .13 .
, .

.11. RPC
RPC
//bench/bw_sunrpc.
1 %#define DEBUG /* */
2 struct data_in {
3 opaque data<>; /* */

281

4 };
5 program BW_SUNRPC_PROG {
6 version BW_SUNRPC_VERS {
7
void BW_SUNRPC(data_in) = 1;
8 } = 1;
9 } = 0x31230001;

A.12. RPC

//bench/bw_sunrpc_client.
1 #include "unpipc.h"
2 #include "bw_sunrpc.h"
3
4

void *buf;
int totalnbytes, xfersize;

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

int
main(int argc, char **argv)
{
int i, nloop, ntowrite;
CLIENT *cl;
data_in in;
if (argc != 6)
err_quit("usage: bw_sunrpc_client <#loops>"
" <#mbytes> <#bytes/write> ");
nloop = atoi(argv[2]);
totalnbytes = atoi(argv[3]) * 1024 * 1024;
xfersize = atoi(argv[4]);
buf = Valloc(xfersize);
Touch(buf, xfersize);
cl = Clnt_create(argv[1], BW_SUNRPC_PROG, BW_SUNRPC_VERS, argv[5]);
Start_time();
for (i = 0; i < nloop; i++) {
ntowrite = totalnbytes;
while (ntowrite > 0) {
in.data.data_len = xfersize;
in.data.data_val = buf;
if (bw_sunrpc_1(&in, cl) == NULL)
err_quit("%s", clnt_sperror(cl, argv[1]));
ntowrite = xfersize;
}
}
printf("bandwidth: %.3f MB/sec\n",
totalnbytes / Stop_time() * nloop);
exit(0);
}

A.13.
RPC
//bench/bw_sunrpc_server.c
1 #include "unpipc.h"
2 #include "bw_sunrpc.h"

282

3
4
5

#ifndef RPCGEN_ANSIC
#define bw_sunrpc_1_svc bw_sunrpc_1
#endif

6
7
8
9
10
11
12

void *
bw_sunrpc_1_svc(data_in *inp, struct svc_req *rqstp)
{
static int nbytes;
nbytes = inp->data.data_len;
return(&nbytes); /* , xdr_void */
}

.4. :
, , Posix System V.
, , . .1.

.14.

.14.

//bench/lat_pipe.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9

void
doit(int readfd, int writefd)
{
char c;
Write(writefd, &c, 1);
if (Read(readfd, &c, 1) != 1)
err_quit("read error");
}

10 int
11 main(int argc, char **argv)
12 {
13 int i, nloop, pipe1[2], pipe2[2];
14 char c;
15 pid_t childpid;
16 if (argc != 2)
17
err_quit("usage: lat_pipe <#loops>");
18 nloop = atoi(argv[1]);
19 Pipe(pipe1);
20 Pipe(pipe2);
21 if ((childpid = Fork()) == 0) {
22
for(;;) { /* */
23
if (Read(pipe1[0], &c, 1) != 1)
24
err_quit("read error");
25
Write(pipe2[1], &c, 1);
26
}
27
it(0);
28 }
29 /* */
30 doit(pipe2[0], pipe1[1]);
31 Start_time();
32 for (i = 0; i < nloop; i++)
33
doit(pipe2[0], pipe1[1]);
34 printf("latency: %.3f usec\n", Stop_time() / nloop);
35 Kill(childpid, SIGTERM);

283

36 exit(0);
37 }

doit
2-9 . . 1 ,
, 1 , . ,
, .


19-20 , fork . , . 4.6 (
). , ,
.


22-27 , .


29-34 doit .
, . doit .
Sparc Solaris 2.6 :

solaris % lat_pipe 10000


latency: 278.633 usec
solaris % lat_pipe 10000
latency: 397.810 usec
solaris % lat_pipe 10000
latency: 392.567 usec
solaris % lat_pipe 10000
latency: 266.572 usec
solaris % lat_pipe 10000
latency: 284.559 usec
324 , . .1.
( ), (write, read, write, read) 1
.
Posix
poaa Posix .15.

. 15.
Posix
//bench/lat_pxmsg.
1 #include "unpipc.h"
2 #define NAME1 "lat_pxmsg1"
3 #define NAME2 "lat_pxmsg2"
4 #define MAXMSG 4 /* 4096 */
5 #define MSGSIZE 1024
6
7
8
9
10
11
12
13

void
doit(mqd_t mqsend, mqd_t mqrecv)
{
char buff[MSGSIZE];
Mq_send(mqsend, buff, 1.0);
if (Mq_receive(mqrecv, buff, MSGSIZE, NULL) != 1)
err_quit("mq_receive error");
}

284

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

int
main(int argc, char **argv)
{
int i, nloop;
mqd_t mq1, mq2;
char buff[MSGSIZE];
pid_t childpid;
struct mq_attr attr;
if (argc != 2)
err_quit("usage: lat_pxmsg <#loops>");
nloop = atoi(argv[1]);
attr.mq_maxmsg = MAXMSG;
attr.mq_msgsize = MSGSIZE;
mq1 = Mq_open(Px_ipc_name(NAME1), O_RDWR |
mq2 = Mq_open(Px_ipc_name(NAME2), O_RDWR |
if ((childpid = Fork()) == 0) {
for(;;) { /* */
if (Mq_receive(mq1, buff, MSGSIZE, NULL)
err_quit("mq_receive error");
Mq_send(mq2, buff, 1.0);
}
exit(0);
}
/* */
doit(mq1, mq2);
Start_time();
for (i = 0; i < nloop; i++)
doit(mq1, mq2);
printf("latency: %.3f usec\n", Stop_time()
Kill(childpid, SIGTERM);
Mq_close(mq1);
Mq_close(mq2);
Mq_unlink(Px_ipc_name(NAMED);
Mq_unlink(Px_ipc_name (NAME2));
exit(0);
}

O_CREAT, FILE_MODE, &attr);


O_CREAT, FILE_MODE, &attr);

!= 1)

/ nloop);

25-28 , . Posix
, mq_receive ,
.
System V
.16 System V.

.16.
System V
//bench/lat_svmsg.c
1 #include "unpipc.h"
2 struct msgbuf p2child = { 1, { 0 } }; /* type = 1 */
3 struct msgbuf child2p = { 2, { 0 } }; /* type = 2 */
4 struct msgbuf inbuf;
5 void
6 doit(int msgid)
7 {
8
Msgsnd(msgid, &p2child, 0, 0);
9
if (Msgrcv(msgid, &inbuf, sizeof(inbuf.mtext), 2, 0) != 0)
10
err_quit("msgrcv error");

285

11 }
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

int
main(int argc, char **argv)
{
int i, nloop, msgid;
pid_t childpid;
if (argc != 2)
err_quit("usage: lat_svmsg <#loops>");
nloop = atoi(argv[1]);
msgid = Msgget(IPC_PRIVATE, IPC_CREAT | SVMSG_MODE);
if ((childpid = Fork()) == 0) {
for(;;) { /* */
if (Msgrcv(msgid, &inbuf, sizeof(inbuf.mtext), 1, 0) != 0)
err_quit("msgrcv error");
Msgsnd(msgid, &child2p, 0, 0);
}
exit(0);
}
/* */
doit(msgid);
Start_time();
for (i = 0; i < nloop; i++)
doit(msgid);
printf("latency: %.3f usec\n", Stop_time() / nloop);
Kill(childpid, SIGTERM);
Msgctl(msgid, IPC_RMID, NULL);
exit(0);
}

, . 1
, 2 . msgrcv doit 2,
. msgrcv 1.

9.3 11.3 , , , , Posix.1


Unix 98 , , .
msgbuf , System V , long,
.

poaa .17. server.
door_call . 1 , .

.17.

//bench/lat_door.c
1 #include "unpipc.h"
2
3
4
5
6
7
8

void
server(void *cookie, char *argp, size_t arg_size,
door_desc_t *dp, size_t n_descriptors)
{
char c;
Door_return(&c, sizeof(char), NULL, 0);
}

9 int
10 main(int argc, char **argv)
11 {
12 int i, nloop, doorfd, contpipe[2];
13 char c;

286

14 pid_t childpid;
15 door_arg_t arg;
16 if (argc != 3)
17
err_quit("usage: lat_door <#loops>");
18 nloop = atoi(argv[2]);
19 unlink(argv[1]);
20 Close(Open(argv[1], O_CREAT | O_EXCL | O_RDWR, FILE_MODE));
21 Pipe(contpipe);
22 if ((childpid = Fork()) == 0) {
23
doorfd = Door_create(server, NULL, 0);
24
Fattach(doorfd, argv[1]);
25
Write(contpipe[1], &c, 1);
26
for(;;) /* = */
27
pause();
28
exit(0);
29 }
30 arg.data_ptr = &c; /* = */
31 arg.data_size = sizeof(char);
32 arg.desc_ptr = NULL;
33 arg.desc_num = 0;
34 arg.rbuf = &c;
35 arg.rsize = sizeof(char);
36 if (Read(contpipe[0], &c, 1) != 1) /* */
37
err_quit("pipe read error");
38 doorfd = Open(argv[1], O_RDWR);
39 Door_call(doorfd, &arg); /* */
40 Start_time();
41 for (i = 0; i < nloop; i++)
42
Door_call(doorfd, &arg);
43 printf("latency: %.3f usec\n", Stop_time() / nloop);
44 Kill(childpid, SIGTERM);
45 unlink(argv[1]);
46 exit(0);
47 }
Sun RPC
Sun RPC : , .
RPC, . 16.11:
. , , . .18 .
16.11, clnt_call ;
.

.18. Sun RPC

//bench/lat_sunrpc_client.
1 #include "unpipc.h"
2 #include "lat_sunrpc.h"
3 int
4 main(int argc, char **argv)
5 {
6
int i, nloop;
7
CLIENT *cl;
8
struct timeval tv;
9
if (argc != 4)
10
err_quit("usage: lat_sunrpc_client <#loops> ");
11 nloop = atoi(argv[2]);
12 cl = Clnt_create(argv[1], BW_SUNRPC_PROG, BW_SUNRPC_VERS, argv[3]);
13 tv.tv_sec = 10;

287

14 tv.tv_usec = 0;
15 Start_time();
16 for (i = 0; i < nloop; i++) {
17
if (clnt_call(cl, NULLPROC, xdr_void, NULL,
18
xdr_void, NULL, tv) != RPC_SUCCESS)
19
err_quit("%s", clnt_sperror(cl, argv[1]));
20 }
21 printf("latency: %.3f usec\n", Stop_time() / nloop);
22 exit(0);
23 }
, .13, . rpcgen
, , . , rpcgen,
, main , .
.5. :
, , (
, . .4 .5), ,
.
Posix
.19 main poa, Posix.

.19.
main Posix
//bench/incr_pxmutex1.
1 #include "unpipc.h"
2 #define MAXNTHREADS 100
3
4
5
6
7
8
9
10

int nloop;
struct {
pthread_mutex_t mutex;
long counter;
} shared = {
PTHREAD_MUTEX_INITIALIZER
};
void *incr(void *);

11 int
12 main(int argc, char **argv)
13 {
14 int i, nthreads;
15 pthread_t tid[MAXNTHREADS];
16 if (argc != 3)
17
err_quit("usage: incr_pxmutex1 <#loops> <#threads>");
18 nloop = atoi(argv[1]);
19 nthreads = min(atoi(argv[2]), MAXNTHREADS);
20 /* */
21 Pthread_mutex_lock(&shared.mutex);
22 /* */
23 Set_concurrency(nthreads);
24 for (i = 0; i < nthreads; i++) {
25
Pthread_create(&tid[i], NULL, incr, NULL);
26 }
27 /* */
28 Start_time();
29 Pthread_mutex_unlock(&shared.mutex);
30 /* */
31 for (i = 0; i < nthreads; i++) {
32
Pthread_join(tid[i], NULL);
33 }

288

34 printf("microseconds: %.0f usec\n", Stop_time());


35 if (shared.counter != nloop * nthreads)
36
printf("error: counter = %ld\n", shared, counter);
37 exit(0);
38 }


4-9 . .

20-26 , ,
. set_concurrency, . incr,
.

27-36 .
, . .20 incr, .

.20. incr,
//bench/incr_pxmutex1.c
39 void *
40 incr(void *arg)
41 {
42 int i;
43 for (i = 0; i < nloop; i++) {
44
Pthread_mutex_lock(&shared.mutex);
45
shared.counter++;
46
Pthread_mutex_unlock(&shared.mutex);
47 }
48 return(NULL);
49 }


44-46 .
.
-
poaa, -, Posix.
, .

, -, Unix 98
Posix.1j. Solaris 2.6 ,
rwlock(3T). , - Posix.
-.
Digital Unix 4.0B - - , tis_rwlock.
, .
.21 main, .22 incr.

.21. main
//bench/incr_rwlock1.c

289

1
2

#include "unpipc.h"
#include /* Solaris */

3
4
5
6
7
8
9
10
11

void Rw_wrlock(rwlock_t *rwptr);


void Rw_unlock(rwlock_t *rwptr);
#define MAXNTHREADS 100
int nloop;
struct {
rwlock_t rwlock; /* Solaris */
long counter;
} shared; /* > USYNC_THREAD */
void *incr(void *);

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

int
main(int argc, char **argv)
{
int i, nthreads;
pthread_t tid[MAXNTHREADS];
if (argc != 3)
err_quit("usage: incr_rwlockl <#loops> <#threads>");
nloop = atoi(argv[1]);
nthreads = min(atoi(argv[2]), MAXNTHREADS);
/* */
Rw_wrlock(&shared.rwlock);
/* */
Set_concurrency(nthreads);
for (i = 0; i < nthreads; i++) {
Pthread_create(&tid[i], NULL, incr, NULL);
}
/* */
Start_time();
Rw_unlock(&shared.rwlock);
/* */
for (i = 0; i < nthreads; i++) {
Pthread_join(tid[i], NULL);
}
printf("microseconds: %.0f usec\n", Stop_time());
if (shared.counter != nloop * nthreads)
printf("error: counter = %ld\n", shared.counter);
exit(0);
}

.22.
-
//bench/incr_rwlock1.c
40 void *
41 incr(void *arg)
42 {
43 int i;
44 for (i = 0; i < nloop; i++) {
45
Rw_wrlock(&shared.rwlock);
46
shared.counter++;
47
Rw_unlock(&shared.rwlock);
48 }
49 return(NULL);
50 }

290

Posix,
Posix ( ). .24 main,
.23 incr.

.23.
Posix
//bench/incr_pxsem1.
37 void *
38 incr(void *arg)
39 {
40 int i;
41 for (i = 0; i < nloop; i++) {
42
Sem_wait(&shared.mutex);
43
shared.counter++;
44
Sem_post(&shared.mutex);
45 }
46 return(NULL);
47 }

.24. main Posix,



//bench/incr_pxsem1.
1 #include "unpipc.h"
2 #define MAXNTHREADS 100
3 int nloop;
4 struct {
5
sem_t mutex; /* */
6
long counter;
7 } shared;
8 void *incr(void *);
9 int
10 main(int argc, char **argv)
11 {
12 int i, nthreads;
13 pthread_t tid[MAXNTHREADS];
14 if (argc != 3)
15
err_quit("usage: incr_pxseml <#loops> <#threads>");
16 nloop = atoi(argv[1]);
17 nthreads = min(atoi(argv[2]), MAXNTHREADS);
18 /* 0 */
19 Sem_init(&shared.mutex, 0, 0);
20 /* */
21 Set_concurrency(nthreads);
22 for (i = 0; i < nthreads; i++) {
23
Pthread_create(&tid[i], NULL, incr, NULL);
24 }
25 /* */
26 Start_time();
27 Sem_post(&shared.mutex);
28 /* */
29 for (i = 0; i < nthreads; i++) {
30
Pthread_join(tid[i], NULL);
31 }

291

32 printf("microseconds: %.0f usec\n", Stop_time());


33 if (shared.counter != nloop * nthreads)
34
printf("error: counter = %ld\n", shared.counter);
35 exit(0);
36 }
18-19 , 0. sem_init, 0, ,
.
20-27 sem_post.
Posix
.26 main, Posix, .25
incr.

.25.
Posix
//bench/incr_pxsem2.c
40 void *
41 incr(void *arg)
42 {
43 int i;
44 for (i = 0; i < nloop; i++) {
45
Sem_wait(shared.mutex);
46
shared.counter++;
47
Sem_post(shared.mutex);
48 }
49 return(NULL);
50 }

.26. main
Posix
//bench/incr_pxsem2.
1 #include "unpipc.h"
2 #define MAXNTHREADS 100
3 #define NAME "incr_pxsem2"
4
5
6
7
8
9

int nloop;
struct {
sem_t *mutex; /* */
long counter;
} shared;
void *incr(void *);

10 int
11 main(int argc, char **argv)
12 {
13 int i, nthreads;
14 pthread_t tid[MAXNTHREADS];
15 if (argc != 3)
16
err_quit("usage: incr_pxsem2 <#loops> <#threads>");
17 nloop = atoi(argv[1]);
18 nthreads = min(atoi(argv[2]), MAXNTHREADS);
19 /* 0 */
20 sem_unlink(Px_ipc_name(NAME)); /* OK */
21 shared.mutex = Sem_open(Px_ipc_name(NAME), O_CREAT | O_EXCL, FILE_MODE, 0);
22 /* */
23 Set_concurrency(nthreads);

292

24 for (i = 0; i < nthreads; i++) {


25
Pthread_create(&tid[i], NULL, incr, NULL);
26 }
27 /* */
28 Start_time();
29 Sem_post(shared.mutex);
30 /* */
31 for (i = 0; i < nthreads; i++) {
32
Pthread_join(tid[i], NULL);
33 }
34 printf("microseconds: %.0f usec\n", Stop_time());
35 if (shared.counter != nloop * nthreads)
36
printf("error: counter = %ld\n", shared.counter);
37 Sem_unlink(Px_ipc_name(NAME));
38 exit(0);
39 }
System V
main , System V, .27, incr .28.

.27. main
System V
//bench/incr_svsem1.c
1 #include "unpipc.h"
2 #define MAXNTHREADS 100
3
4
5
6
7
8
9

int nloop;
struct {
int semid;
long counter;
} shared;
struct sembuf postop, waitop;
void *incr(void *);

10 int
11 main(int argc, char **argv)
12 {
13 int i, nthreads;
14 pthread_t tid[MAXNTHREADS];
15 union semun arg;
16 if (argc != 3)
17
err_quit("usage: incr_svseml <#loops> <#threads>");
18 nloop = atoi(argv[1]);
19 nthreads = min(atoi(argv[2]), MAXNTHREADS);
20 /* 0 */
21 shared.semid = Semget(IPC_PRIVATE, 1, IPC_CREAT | SVSEM_MODE);
22 arg.val =0;
23 Semctl(shared.semid, 0, SETVAL, arg);
24 postop.sem_num = 0; /* semop */
25 postop.sem_op = 1;
26 postop.sem_flg = 0;
27 waitop.sem_num = 0;
28 waitop.sem_op = 1;
29 waitop.sem_flg = 0;
30 /* */
31 Set_concurrency(nthreads);
32 for (i = 0; i < nthreads; i++) {

293

33
Pthread_create(&tid[i], NULL, incr, NULL);
34 }
35 /* */
36 Start_time();
37 Semop(shared.semid, &postop, 1); /* up by 1 */
38 /* */
39 for (i = 0; i < nthreads; i++) {
40
Pthread_join(tid[i], NULL);
41 }
42 printf("microseconds: %.0f usec\n", Stop_time());
43 if (shared.counter != nloop * nthreads)
44
printf("error: counter = %ld\n", shared, counter);
45 Semctl(shared.semid, 0, IPC_RMID);
46 exit(0);
47 }

.28.
System V
//bench/incr_svsem1.c
48 void *
49 incr(void *arg)
50 {
51 int i;
52 for (i = 0; i < nloop; i++) {
53
Semop(shared.semid, &waitop, 1);
54
shared.counter++;
55
Semop(shared.semid, &postop, 1);
56 }
57 return(NULL);
58 }
20-23 , .
24-29 semop: , . ,
sem_flg 0: SEM_UNDO .

System V SEM_UNDO
poa .27 , sem_flg semop SEM_UNDO,
0. .
fcntl
poaa fcntl . main .30.
, 1, fcntl ,
. ( writew_lock
, ), .
incr, , .29.

.29.
fcntl
//bench/incr_fcntl1.e
44 void *
45 incr(void *arg)
46 {
47 int i;
48 for (i = 0; i < nloop; i++) {
49
Writew_lock(shared.fd, 0, SEEK_SET, 0);
50
shared.counter++;
51
Un_lock(shared.fd, 0, SEEK_SET, 0);

294

52 }
53 return(NULL);
54 }

.30. main
fcntl
//bench/incr_fcntl1.e
4 #include "unpipc.h"
5 #define MAXNTHREADS 100
6
7
8
9
10
11

int nloop;
struct {
int fd;
long counter;
} shared;
void *incr(void *);

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

int
main(int argc, char **argv)
{
int i, nthreads;
char *pathname;
pthread_t tid[MAXNTHREADS];
if (argc != 4)
err_quit("usage: incr_fcntll <#loops> <#threads>");
pathname = argv[1];
nloop = atoi(argv[2]);
nthreads = min(atoi(argv[3]), MAXNTHREADS);
/* */
shared.fd = Open(pathname, O_RDWR | O_CREAT | O_TRUNC, FILE_MODE);
Writew_lock(shared.fd, 0, SEEK_SET, 0);
/* */
Set_concurrency(nthreads);
for (i = 0; i < nthreads; i++) {
Pthread_create(&tid[i], NULL, incr, NULL);
}
/* */
Start_time();
Un_lock(shared.fd, 0, SEEK_SET, 0);
/* */
for (i = 0; i < nthreads; i++) {
Pthread_join(tid[i], NULL);
}
printf("microseconds: %.0f usec\n", Stop_time());
if (shared.counter != nloop * nthreads)
printf("error: counter = %ld\n", shared.counter);
Unlink(pathname);
exit(0);
}

15-19 .
. , NFS (
, NFS NFS).
.6. :
.
. .
, my_shm,
.31.

295

.31.

//lib/my_shm.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

void *
my_shm(size_t nbytes)
{
void *shared;
#if defined(MAP_ANON)
shared = mmap(NULL, nbytes, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_SHARED, 1, 0);
#elif defined(HAVE_DEV_ZERO)
int fd;
/* /dev/zero */
if ((fd = open("/dev/zero", O_RDWR)) == 1)
return(MAP_FAILED);
shared = mmap(NULL, nbytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
#else
# error cannot determine what type of anonymous shared memory to use
#endif
return(shared); /* */
}

MAP_ANON ( 12.4), .
/dev/zero ( 12.5).
,
fork. 10.12.
Posix: ( )
PTHREAD_ PROCESS_SHARED. .
- Posix: ( )
PTHREAD_PROCESS_SHARED.
Posix, : ( ),
sem_init ( , ).
Posix: sem_open , sem_open
, , fork.
System V: , ,
. .
fcntl: .
Posix.
Posix
main Posix . .32.

.32. main

//bench/incr_pmutex5.
1 #include "unpipc.h"
2 #define MAXNPROC 100
3
4
5
6
7
8

int nloop;
struct shared {
pthread_mutex_t mutex;
long counter;
} *shared; /* , */
void *incr(void *);

296

9 int
10 main(int argc, char **argv)
11 {
12 int i, nprocs;
13 pid_t childpid[MAXNPROC];
14 pthread_mutexattr_t mattr;
15 if (argc != 3)
16
err_quit("usage: incr_pxmutex5 <#loops> <#processes>");
17 nloop = atoi(argv[l]);
18 nprocs = min(atoi(argv[2]), MAXNPROC);
19 /* */
20 shared = My_shm(sizeof(struct shared));
21 /* */
22 Pthread_mutexattr_init(&mattr);
23 Pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
24 Pthread_mutex_init(&shared->mutex, &mattr);
25 Pthread_mutexattr_destroy(&mattr);
26 Pthread_mutex_lock(&shared->mutex);
27 /* */
28 for (i = 0; i < nprocs; i++) {
29
if ((childpid[i] = Fork()) == 0) {
30
incr(NULL);
31
exit(0);
32
}
33 }
34 /* :
*/
35 Start_time();
36 Pthread_mutex_unlock(&shared->mutex);
37 /* */
38 for (i = 0; i < nprocs; i++) {
39
Waitpid(childpid[i], NULL, 0);
40 }
41 printf("microseconds: %.0f usec\n", Stop_time());
42 if (shared->counter != nloop * nprocs)
43
printf("error: counter = %ld\n", shared->counter);
44 exit(0);
45 }
19-20 , shared . my_shm,
.31.
21-26 , ,
pthread_mutex_init PTHREAD_PROCESS_SHARED. .
27-36 .
37-43 , .

.33.

//bench/incr_pxmutex5.
46 void *
47 incr(void *arg)
48 {
49 int i;
50 for (i = 0; i < nloop; i++) {
51
Pthread_mutex_lock(&shared->mutex);
52
shared->counter++;
53
Pthread_mutex_unlock(&shared->mutex);

297

54 }
55 return(NULL);
56 }


.1.
, . Unix , ,
- , fork. Unix
.
, fork :
fork . , . .
(copy-on-write), ,
, , , fork ;
IPC fork.
: fork. .
. (lightweight processes), ,
. .
, ,
. . :
;
;
();
;
;
.
:
;
, PC ;
( );
errno;
;
.
.2. :
.

pthread_create
poa exec , , (initial thread).
pthread_create:

#include
int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*func) (void
*), void *arg);
/* 0 ,
*/
, pthread_t.
tid.
: , , . .
pthread_attr_t, , .
. attr .
, , , (thread start function).
( pthread_exit), ( ).
func, arg. ,
.
func arg. void,
. .
Posix 0 .
, 1 errno , Pthread
. , pthread_create - oae
, EAGAIN. Pthread errno. ,
().

pthread_join
- , pthread_join. Unix, , pthread_create
fork, a pthread_join waitpid:

#include
int pthread_join(pthread_t tid, void **status);
/* 0 ,
*/
, . ,
( waitpid 1 ).
status , ( ) , status.

298

pthread_self
, . pthread_create
pthread_join. pthread_self:

#include
pthread_t pthread_self(void);
/* */
pthread_self getpid Unix.

pthread_detach
( ), .
, - pthread_join.
-. . .
, .
pthread_detach :

#include
int pthread_detach(pthread_t tid);
/* 0
*/

pthread_detach(pthread_self());

pthread_exit
pthread_exit:

#include
void pthread_exit(void *status);
/* */
, ,
pthread_join.
status ( ),
.
:
( pthread_create) return.
void, ;
main exit _exit. ,
.


.1. unpipc.h
unpipc.h, .1.[1]
, poa , .
MAXLINE ANSI , ( px_ipc_name), .
.

.1. unpipc.h
//lib/unpipc.h
1
/* . */
2
#ifndef __unpipc_h
3
#define __unpipc_h
4
5

#include "../config.h" /* */
/* "../config.h" configure */

6
7
8
9

/* #include,
../aclocal.m4 ../configure.in. configure */
#include /* */
#include /* timeval{} select() */

10

#include /* timespec{} pselect() */

299

11
12
13
14
15
16
17
18
19
20

#include
#include /* */
#include /* PIPE_BUF */
#include
#include
#include
#include
#include /* S_xxx */
#include
#include

21
22
23

#ifdef HAVE_MQUEUE_H
#include /* Posix */
#endif

24
25
26
27
28
29

#ifdef HAVE_SEMAPHORE_H
#include /* Posix */
#ifndef SEM_FAILED
#define SEM_FAILED ((sem_t *)(-1))
#endif
#endif

30
31
32

#ifdef HAVE_SYS_MMAN_H
#include /* Posix */
#endif

33
34
35

#ifndef MAP_FAILED
#define MAP_FAILED ((void *)(-1))
#endif

36
37
38

#ifdef HAVE_SYS_IPC_H
#include /* System V IPC */
#endif

39
40
41

#ifdef HAVE_SYS_MSG_H
#include /* System V */
#endif

42 #ifdef HAVE_SYS_SEM_H
43 #ifdef __bsdi__
44 #undef HAVE_SYS_SEM_H /* : semctl() BSDI's
*/
45 #else
46 #include /* System V */
47 #endif
48 #ifndef HAVE_SEMUN_UNION /* $$.It semun$$ */
49 union semun { /* semctl() */
50
int val;
51
struct semid_ds *buf;
52
unsigned short *array;
53 };
54 #endif
55 #endif /* HAVE_SYS_SEM_H */
56
57
58

#ifdef HAVE_SYS_SHM_H
#include /* System V */
#endif

300

59
60
61

#ifdef HAVE_SYS_SELECT_H
#include /* */
#endif

62
63
64

#ifdef HAVE_POLL_H
#include /* */
#endif

65
66
67

#ifdef HAVE_STROPTS_H
#include /* */
#endif

68
69
70

#ifdef HAVE_STRINGS_H
#include /* */
#endif

71
72
73
74
75
76
77
78
79

/* ioctl :
* , , .
*/
#ifdef HAVE_SYS_IOCTL_H
#include
#endif
#ifdef HAVE_SYS_FILIO_H
#include
#endif

80
81
82
83
84
85
86
87
88
89
90
91

#ifdef HAVE_PTHREAD_H
#include
#endif
#ifdef HAVE_DOOR_H
#include /* Solaris */
#endif
#ifdef HAVE_RPC_RPC_H
#ifdef _PSX4_NSPACE_H_TS /* Digital Unix 4.0b */
#undef SUCCESS
#endif
#include /* Sun RPC */
#endif

92
93
94
95

/* bzero() , */
#ifndef HAVE_BZERO
#define bzero(ptr,n) memset(ptr, 0, n)
#endif

96 /* Posix.1g , INFTIM .
97
.
98
, INFTM .

99
, , 1 */
100 #ifndef INFTIM
101 #define INFTIM (-1) /* */
102 #ifdef HAVE_POLL_H
103 #define INFTIM_UNPH /* unpxti.h ,
*/
104 #endif
105 #endif

301

*/

106 /* */
107 #ifndef _ /* */
108 #define PATH_MAX 1024 /*
109
110
111
112
113
114
115
116
117
118
119
120
121
122

#endif
#define MAX_PATH 1024
#define MAXLINE 4096 /* */
#define BUFFSI2E 8192 /* */
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
/* */
#define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)
/* */
#define SVMSG_MODE (MSG_R | MSG_W | MSG_R>>3 | MSG_R>>6)
/* System V */
#define SVSEM_MODE (SEM_R | SEM_A | SEM_R>>3 | SEM_R>>6)
/* System V */
#define SVSHM_MODE (SHM_R | SHM_W | SHM_R>>3 | SHM_R>>6)
/* System V */

123
124
125
126

typedef void Sigfunc(int); /* */


#ifdef HAVE_SIGINFO_T_STRUCT
typedef void Sigfunc_rt(int, siginfo_t*, void*);
#endif

127
128
129
130
131
132
133
134

#define min(a,b) ((a) < (b) ? (a) : (b))


#define max(a,b) ((a) > (b) ? (a) : (b))
#ifndef HAVE_TIMESPEC_STRUCT
struct timespec {
time_t tv_sec; /* */
long tv_nsec; /* */
};
#endif

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

/*
- open(), mq_open(), sem_open()
va_XXX().
mode_t,
BSD/OS,
16- .
16-
32-. .
.
*/
#ifdef __bsdi__
#define va_mode_t int
#else
#define va_mode_t mode_t
#endif

150
151
152
153
154
155
156
157

/* */
#define read_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLK, F_RDLCK, offset, whence, len)
#define readw_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLKW, F_RDLCK, offset, whence, len)
#define write_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLK, F_WRLCK, offset, whence, len)
#define writew_lock(fd, offset, whence, len) \

302

158 lock_reg(fd, F_SETLKW, F_WRLCK, offset, whence, len)


159 #define un_lock(fd, offset, whence, len) \
160 lock_reg(fd, F_SETLK, F_UNLCK, offset, whence, len)
161 #define is_read_lockable(fd, offset, whence, len) \
162 lock_test(fd, F_RDLCK, offset, whence, len)
163 #define is_write_lockable(fd, offset, whence, len) \
164 lock_test(fd. F_WRLCK, offset, whence, len)
B.2. config.h
poa GNU autoconf, .
ftp://prep.ai.mit.edu/pub/gnu. configure, , aye poay .
: System V, uint8_t, gethostname .
. config.h, unpipc.h . .2
config.h Solaris 2.6 gcc.
, #define, , .
.

.2. config.h Solaris


2.6
//sparc-sun-solaris2.6/config.h
1 /* config.h. configure. */
2 /* ,
*/
3 #define CPU_VENDOR_OS "sparc-sun-solaris2.6"
4 #define HAVE_DOOR_H 1 /* */
5 #define HAVE_MQUEUE_H 1 /* */
6 #define HAVE_POLL_H 1 /**/
7 #define HAVE_PTHREAD_H 1 /* */
8 #define HAVE_RPC_RPC_H 1 /* */
9 #define HAVE_SEMAPHORE_H 1 /* semaphore.h> */
10 #define HAVE_STRINGS_H 1 /* */
11 #define HAVE_SYS_FILIO_H 1 /* */
12 #define HAVE_SYS_IOCTL_H 1 /* */
13 #define HAVE_SYS_IPC_H 1 /* */
14 #define HAVE_SYS_MMAN_H 1 /* */
15 #define HAVE_SYS_MSG_H 1 /* */
16 #define HAVE_SYS_SEM_H 1 /* */
17 #define HAVE_SYS_SHM_H 1 /* */
18 #define HAVE_SYS_SELECT_H 1 /* */
19 /* #undef HAVE_SYS_SYSCTL_H */ /* */
20 #define HAVE_SYS_TIME_H 1 /* */

21 /* , */
22 #define TIME_WITH_SYS_TIME 1
23
24
25
26
27
28
29
30

/* , */
#define HAVE_BZERO 1
#define HAVE_FATTACH 1
#define HAVE_POLL 1
/* #undef HAVE_PSELECT */
#define HAVE_SIGWAIT 1
#define HAVE_VALLOC 1
#define HAVE_VSNPRINTF 1

31
32
33
34
35

/* , */
#define HAVE_GETHOSTNAME_PROTO 1 /* */
#define HAVE_GETRUSAGE_PROTO 1 /* */
/* #undef HAVE_PSELECT_PROTO */ /* */
#define HAVE SHM_OPEN_PROTO 1 /* */

303

36 #define HAVE_SNPRINTF_PROTO 1 /* */
37 #define HAVE_THR_SETCONCURRENCY_PROTO 1 /* */
38
39
40
41

/* , */
#define HAVE_SIGINFO_T_STRUCT 1 /* */
#define HAVE_TIMESPEC_STRUCT 1 /* */
/* #undef HAVE_SEMUN_UNION */ /* */

42 /* */
43 #define HAVE_DEV_ZERO 1
44
45
46
47
48
49
50
51
52

/*
/*
/*
/*
/*
/*
/*
/*
/*

*/
#undef int8_t */ /* */
#undef intl6_t */ /* */
#undef int32_t */ /* */
#undef uint8_t */ /* */
#undef uintl6_t */ /* */
#undef uint32_t */ /* */
#undef size_t */ /* */
#undef ssize_t */ /* */

53 #define POSIX_IPC_PREFIX "/"


54 #define RPCGEN_ANSIC 1 /* , rpcgen */
..
, . ,
, , :

if (_) err_sys( printf );


:

if (_) {
char buff[200];
snprintf(buff,
sizeof(buff),
);
perror(buff);
exit(1);
}

printf

, ANSI .
7.3 [ 11 ] .
.1 . daemon_proc ,
syslog (. 12 [24]); .

.1.

err_dump
err_msg
err_quit
err_ret
err_sys

strerror(errno)?

?
abort();
return;
exit(1);
return;
exit(1);

syslog
LOG_ERR
LOG_INFO
LOG_ERR
LOG_INFO
LOG_ERR

.3 . .1.

.3.
//lib/error.
1 #include "unpipc.h"
2 #include /* ANSI */
3 #include /* syslog() */
4
5

int daemon_proc; /* daemon_init() */


static void err_doit(int, int, const char*, va_list);

304

6
7
8
9
10
11
12
13
14
15
16

/* .
* . */
void
err_ret(const char *fmt, ...)
{
va_list ;
va_start(ap, fmt);
err_doit(1, LOG_INFO, fmt, ap);
va_end(ap);
return;
}

17
18
19
20
21
22
23
24
25
26
27

/* .
* . */
void
err_sys(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, LOG_ERR, fmt, );
va_end(ap);
exit(1);
}

28
29
30
31
32
33
34
35
36
37
38
39

/* .
* , , . */
void
err_dump(const char *fmt, ...)
{
va_list ;
va_start(ap, fmt);
err_doit(1, LOG_ERR, fmt, ap);
va_end(ap);
abort(); /* */
exit(1); /* */
}

40
41
42
43
44
45
46
47
48
49
50

/* .
* . */
void
err_msg(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, LOG_INFO, fmt, ap);
va_end(ap);
return;
}

51
52
53
54
55
56
57

/* .
* . */
void
err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);

305

58 err_doit(0, LOG_ERR, fmt, ap);


59 va_end(ap);
60 exit(1);
61 }
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

/* .
* "errnoflag" "level". */
static void
err_doit(int errnoflag, int level, const char *fmt, va_list ap)
{
int errno_save, n;
char buf[MAXLINE];
errno_save = errno; /* */
#ifdef HAVE_VSNPRINTF
vsnprintf(buf, sizeof(buf), fmt, ); /* */
#else
vsprintf(buf, fmt, ); /* */
#endif
n = strlen(buf);
if (errnoflag)
snprintf(buf+n, sizeof(buf)-n, ": %s", strerror(errno_save));
strcat(buf, "\n");
if (daemon_proc) {
syslog(level, buf);
} else {
fflush(stdout); /* stdout stderr */
fputs(buf, stderr);
fflush(stderr);
}
return;
}



1
1. O_APPEND open fopen.
, . . . 60-61 [21]
. , .
2. - :

#ifdef REENTRANT
#define errno (*_errno())
#else
extern int errno;
#endif
_REENTRANT, errno _errno, errno
. , , ( 23.5 [24]). REENTRANT ,
errno .
2
1. / .
2.4.
2. O_CREAT | O_EXCL, , .
EEXIST, open , O_CREAT O_EXCL ,
, ENOENT, - .
3
1. poa .1.[1]

.1.

//svmsg/slotseq.c
1 #include "unpipc.h"
2

int

306

3 main(int argc, char **argv)


4 {
5
int i, msqid;
6
struct msqid_ds info;
7
for (i = 0; i < 10; i++) {
8
msqid = Msgget(IPC_PRIVATE, SVMSG_MODE | IPC_CREAT);
9
Msgctl(msqid, IPC_STAT, &info);
10
printf("msqid = %d, seq = %lu\n", msqid, info.msg_perm.seq);
11
Msgctl(msqid, IPC_RMID, NULL);
12 }
13 exit(0);
14 }
2. msgget , 20
3.2, 1000. ,
, 0, 1.
3. .2.

.2.
msgget
//svmsg/testumask.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9

int
main(int argc, char **argv)
{
Msgget(IPC_PRIVATE, 0666 | IPC_CREAT | IPC_EXCL);
unlink("/tmp/fifo.1");
Mkfifo("/tmp/fifo.1", 0666);
exit(0);
}

poay, , 2 ( )
FIFO, :

solaris % umask
02
solaris % testumask
solaris % ls l /tmp/fifo.1
prw-rw-r-- 1 rstevens other1 0 Mar 25 16:05 /tmp/fifo.1
solaris % ipcs q
IPC status from as of Wed Mar 25 16:06:03 1998
T ID KEY
MODE
OWNER
GROUP
Message Queues:
q 200 00000000 rw-rw-rw rstevens other1
4. ftok , . IPC_PRIVATE
, , - , .
5. :

solaris % find / links 1 not type l print | xargs n1 ftok1 > temp.1
solaris % wc l temp.1
109351 temp.1
solaris % sort +0 1 temp.1 | nawk '{ if (lastkey== $1) print lastline,
lastline = $0 lastkey = $1 }' > temp.2
solaris % wc l temp.2 82188 temp.2

$0

find , ( ),
( stat , ). (75,2%) , Solaris 2.x
12 . 4096 . ,
4096, 8192, 12288 16384 IPC ( ).
, ftok BSD/OS, ,
849 ( 1%).
4
1. fd[1] , read
, . fd[1] ,
read fd[1] 0.

307

2. , FIFO open mkfifo,


.
3.

solaris % mainopen 2>temp.stderr


/etc/ntp.conf > /myfile
solaris % cat temp.stderr
sh: /myfile: cannot create
, popen , fgets .
.
5. open, :

readfifo = Open(SERV_FIFO, O_RDONLY | O_NONBLOCK, 0);


, open, .
readline, O_NONBLOCK readfifo , .
6. , .
open , 4.11, .
7. .
8. .3 .

.. fstat
FIFO?
//pipe/test1l.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

int
main(int argc, char **argv)
{
int fd[2],
char buff[7];
struct stat info;
if (argc != 2)
err_quit("usage: test1 ");
Mkfifo(argv[1], FILE_MODE);
fd[0] = Open(argv[1], O_RDONLY | O_NONBLOCK);
fd[1] = Open(argv[1], O_WRONLY | O_NONBLOCK);
/* 4check sizes when FIFO is empty */
Fstat(fd[0], &info);
printf("fd[0]: st_size = %ld\n", (long) info.st_size);
Fstat(fd[1], &info);
printf("fd[1]: st_size = %ld\n", (long) info.st_size);
Write(fd[1], buff, sizeof(buff));
Fstat(fd[0], &info);
printf("fd[0]: st_size = %ld\n", (long) info.st_size);
Fstat(fd[1], &info);
printf("fd[1]: st_size = %ld\n", (long) info.st_size);
exit(0);
}

9. select , write SIGPIPE.


[24, . 153-155]; , select , ,
read write. .4 poa.

.4. select
?
//pipe/test2.c
1 #include "unpipc.h"
2
3

int
main(int argc, char **argv)

308

4 {
5
int fd[2], n;
6
pid_t childpid;
7
fd_set wset;
8
Pipe(fd);
9
if ((childpid = Fork()) == 0) { /* child */
10
printf("child closing pipe read descriptor\n");
11
Close(fd[0]);
12
sleep(6);
13
exit(0);
14 }
15 /* 4parent */
16 Close(fd[0]); /* */
17 sleep(3);
18 FD_ZERO(&wset);
19 FD_SET(fd[1], &wset);
20 n = select(fd[1] + 1, NULL, &wset, NULL, NULL);
21 printf("select returned %d\n", n);
22 if (FD_ISSET(fd[1], &wset)) {
23
printf("fd[1] writable\n");
24
Write(fd[1], "hello", 5);
25 }
26 exit(0);
27 }
5
1. , , mq_getattr .
, .
2. , .
3. , .
4. GNU Solaris 2.6 ( sysconf) :

test1.c:13: warning: int format, long int arg (arg 2)


test1.c:13: warning: int format, long int arg (arg 3)
5. Solaris 2.6 1000000 10 . 20000536 ,
, poa 5.4: 10 , 8 (, ), 2
(, 4) 536 . mq_open ,
ps, 1052 , 20 . , Posix
, mq_open .
Digital Unix 4.0B.
6. , , ANSI memXXX. 1989 3.159-1989 (ISO/IEC
9899:1990) ( ), Technical Corrigendum Number 1 , 0
( ). ,
http://www.lysator.liu.se/c/.
7. (. , .15).
4.4 Posix , , , .
8. , ,
. ,
.
9. , .
10. main select, .
select, EINTR. , -
Select select, .5. [24, . 124]
.

.5. Select,
EINTR
//lib/wrapunix.c
313 int
314 Select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
315 struct timeval *timeout)
316 {
317 int n;
318 again:
319 if ( (n = select(nfds, readfds, writefds, exceptfds, timeout)) < 0) {
320
if (errno == EINTR)

309

321
goto again;
322 else
323
err_sys("select error");
324 } else if (n == 0 && timeout == NULL)
325
err_quit("select returned 0 with no timeout");
326 return(n); /* 0 - */
327 }
6
1. ( ).
, , ,
, . , ftok, ,
(), .
2. 0 , 1,
init.
3. . 6.2 -.
(. 6.3), .
7
2. , , , , exit
.
3. Solaris 2.6 destroy , , init
. Digital Unix 4.0B , . destroy
. Digital Unix 4.0B attr_t , , Solaris 2.6
.
9
1. , 20, .
2.

setvbuf(stdout, NULL, _IONBF, 0);


main for. , printf .
, printf write.
3. printf

snprintf(line, sizeof(line), "%s: pid = 3.1d, seq# = %d\n", argv[0], (long) pid,
seqno);
for (ptr = line; (c = *ptr++) != 0) putchar(c);
, a ptr char*. setvbuf ,
. ,
. .
4. ,
.
5. , fcntl.
fcntl : F_SETLKW ( ) F_SETLK (
).
6. poaa loopfcntlnonb , , ,
fcntl. loopnonenonb, . 9.5,
write read EAGAIN. :

read error: Resource temporarily unavailable


write error: Resource temporarily unavailable
, EAGAIN,

solaris % grep Resource /usr/include/sys/errno.h


#define EAGAIN 11 /* Resource temporarily unavailable */
7. Solaris 2.6 16%, 20%.
, , .
8. , .
9. , O_TRUNC, .
, , .
10. SEEK_SET. SEEK_CUR , ,
1 seek. 1 seek, fcntl, ,
lseek. , . ,
SEEK_END, , ,
.
10
1. Solaris 2.6:

solaris % deadlock 100


prod: calling sem_wait(nempty) i=0
prod: got sem_wait(nempty)
prod: calling sem_wait(mutex)
prod: got sem_wait(mutex), storing 0
prod: calling sem_wait(nempty) i=1
prod: got sem_wait(nempty)
prod: calling sem_wait(mutex)
prod: got sem_wait(mutex), storing 1
prod: calling sem_wait(nempty) , ,

310

cons:
cons:
cons:
cons:
cons:
cons:
cons:
cons:
cons:
cons:
cons:
cons:
cons:
prod:
prod:

calling sem_wait(mutex) i=0


got sem_wait(mutex)
calling sem_wait(nstored)
got sem_wait(nstored)
fetched 0
calling sem_wait(mutex) i=1
got sem_wait(mutex)
calling sem_wait(nstored)
got sem_wait(nstored)
fetched 1
calling sem_wait(mutex)
got sem_wait(mutex)
calling sem_wait(nstored) . .
got sem_wait(nempty)
calling sem_wait(mutex)
.

2. , sem_open: , .
, sem_open, .
3. . , . poaa
, .
4. 1, , malloc
. open , close error -
. 1, , close (
), .
5. , close , errno.
, - .
6. , mkfifo , .
, FIFO . mkfif EEXIST.
7. poae 10.22 , 10.28, ,
. , , , ,
sem_wait, (
).
8. .6 . Solaris 2.6 Digital Unix 4.0B
EINTR.

.6. sem_wait EINTR?


//pxsem/testeintr.c
1 #include "unpipc.h"
2 #define NAME "testeintr"
3 static void sig_alrm(int);
4 int
5 main(int argc, char **argv)
6 {
7
sem_t *sem1, sem2;
8
/* */
9
sem_unlink(Px_ipc_name(NAME));
10 sem1 = Sem_open(Px_ipc_name(NAME), O_RDWR | O_CREAT | _EXCL,
11
FILE_MODE, 0);
12 Signal(SIGALRM, sig_alrm);
13 alarm(2);
14 if (sem_wait(sem1) == 0)
15
printf("sem_wait returned 0?\n");
16 else
17
err_ret("sem_wait error");
18 Sem_close(sem1);
19 /* */
20 Sem_init(&sem2, 1, 0);
21 alarm(2);
22 if (sem_wait(&sem2) == 0)
23
printf("sem_wait returned 0?\n");
24 else
25
err_ret("sem_wait error");

311

26 Sem_destroy(&sem2);
27 exit(0);
28 }
29
30
31
32
33
34

static void
sig_alrm(int signo)
{
printf("SIGALRM caught\n");
return;
}

FIFO EINTR, sem_wait read, .


, sem_wait pthread_cond_wait,
. System V EINTR, sem_wait semop,
.
9. ( 10.25) , write.
, pthread_XXX
. System V ( 10.41) , semop
Unix 98.
11
1. :

< semid = Semget(Ftok(argv[optind], 0), 0, 0);

> semid = atol(argv[optind]);


2. ftok , Ftok. my_lock ftok semget, ,
ENOENT, , .
12
1. 4096 ( 36864), (36863) SIGSEGV,
32768 . , , ,
.
2. . .1 System V, . .2 Posix. memcpy
mq_send ( 5.26), mq_receive ( 5.28).

. .1. System V

. .2. Posix, mmap


3. read /dev/zero . , ,
( /dev/null).
4. 4 ( 32- ).
5. .7 .

312

.7. select
System V
//shm/svmsgread.c
1 #include "unpipc.h"
2 #define MAXMSG (8192 + sizeof(long))
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
47
46
48
49
50

int
main(int argc, char **argv)
{
int pipe1[2], pipe2[2], mqid;
char c;
pid_t childpid;
fd_set rset;
ssize_t n, nread;
struct msgbuf *buff;
if (argc != 2)
err_quit("usage: svmsgread ");
Pipe(pipe1); /* */
Pipe(pipe2);
buff = My_shm(MAXMSG); /* */
if ((childpid = Fork()) == 0) {
Close(pipe1[1]); /* child */
Close(pipe2[0]);
mqid = Msgget(Ftok(argv[1], 0), MSG_R);
for(;;) {
/* , */
nread = Msgrcv(mqid, buff, MAXMSG, 0, 0);
Write(pipe2[1], &nread, sizeof(ssize_t));
/* */
if ((n = Read(pipe1[0], &c, 1)) != 1)
err_quit("child: read on pipe returned %d", n);
}
exit(0);
} /* $$.bp$$ */
/* parent */
Close(pipe1[0]);
Close(pipe2[1]);
FD_ZERO(&rset);
FD_SET(pipe2[0], &rset);
for(;;) {
if ((n = select(pipe2[0] + 1, &rset, NULL, NULL, NULL)) != 1)
err_sys("select returned %d", n);
if (FD_ISSET(pipe2[0], &rset)) {
n = Read(pipe2[0], &nread, sizeof(ssize_t)); /* *INDENT-OFF* */
if (n != sizeof(ssize_t))
err_quit("parent: read on pipe returned %d", n); /* *INDENT-ON* */
printf("read %d bytes, type = %ld\n", nread, buff->mtype);
Write(pipe1[1], &c, 1);
} else
}
err_quit("pipe2[0] not ready");
Kill(childpid, SIGTERM);
exit(0);
}

13
1. .8 12.6, .9 12.7. ,
poae ftruncate; lseek write .

313

.8.

//pxshra/test1.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

int
main(int argc, char **argv)
{
int fd, i;
char *ptr;
size_t shmsize, mmapsize, pagesize;
if (argc != 4)
err_quit("usage: test1 ");
shmsize = atoi(argv[2]);
mmapsize = atoi(argv[3]);
/* shm: ; */
fd = Shm_open(Px_ipc_name(argv[1]), O_RDWR | O_CREAT | O_TRUNC,
FILE_MODE);
Ftruncate(fd, shmsize); /* $$.bp$S */
ptr = Mmap(NULL, mmapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Close(fd);
pagesize = Sysconf(_SC_PAGESIZE);
printf("PAGESIZE = %ld\n", (long) pagesize);
for (i = 0; i < max(shmsize, mmapsize); i += pagesize) {
printf("ptr[%d] = %d\n", i, ptr[i]);
ptr[i] = 1;
printf("ptr[%d] = %d\n", i + pagesize 1, ptr[i + pagesize 1]);
ptr[i + pagesize 1] = 1;
}
printf("ptr[%d] =%d\n", i, ptr[i]);
exit(0);
}

.9.

//pxshm/test2.c
1 #include "unpipc.h"
2 #define FILE "test.data"
3 #define SIZE 32768
4 int
5 main(int argc, char **argv)
6 {
7
int fd, i;
8
char *ptr;
9
/* , */
10 fd = Shm_open(Px_ipc_name(FILE), O_RDWR | O_CREAT | O_TRUNC, FILE_MODE);
11 ptr = Mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
12 for (i = 4096; i <= SIZE; i += 4096) {
13
printf("setting shm size to %d\n", i);
14
Ftruncate(fd, i);
15
printf("ptr[%d] = %d\n", i-1, ptr[i-1]);
16 }

314

17 exit(0);
18 }
2. *ptr++ , , mmap, ,
munmap. , .
14
1. :

1313
< id = Shmget(Ftok(argv[1], 0), 0, SVSHM_MORE);

> id = atol(argv[1]);
15
1. data_size + (desc_numxsizeof(door_desc_t)) .
2. fstat . , door_inf EBADF:

solaris % doorinfo /etc/passwd


door_info error: Bad file number
3. . Posix , sleep .
4. (, , ), , ,
.
5. door_call - , , ,
. 15.18 , ,
, . sleep(6) ,
.
6. :

solaris % server6 /tmp/door6


my_thread: created sever thread 4
door_bind error: Bad file number
20 , 5 . .
7. . , , , 15.26.
pthread_setcancelstate , , , .
8. , (, 15.6) , door_revoke .
door_revoke , . ( 15.1)
:

solaris % client8 /tmp/door8 88


result: 7744
solaris % client8 /tmp/door8 99
door_call error: Bad file number
, door_revoke. EBADF.
9. fd , cooki, door_create
. .10 .

.10. cookie

//doors/server9.c
1 #include "unpipc.h"
2
3
4
5
6
7
8
9
10
11
12

void
servproc(void *cookie, char *dataptr, size_t datasize,
door_desc_t *descptr, size_t ndesc)
{
long arg, result;
Door_revoke(*((int *) cookie));
arg = *((long *) dataptr);
printf("thread id %ld, arg = %ld\n", pr_thread_id(NULL), arg);
result = arg * arg;
Door_return((char *) &result, sizeof(result), NULL, 0);
}

13 int
14 main(int argc, char **argv)
15 {
16 int fd;
17 if (argc != 2)

315

18
err_quit("usage: server9 ");
19 fd = Door_create(servproc, &fd, 0);
20 unlink(argv[1]);
21 Close(Open(argv[1], O_CREAT | O_RDWR, FILE MODE));
22 Fattach(fd, argv[1]);
23 for(;;)
24
pause();
25 }
5.17 5.18, cookie my_thread ( door_info_t),
( door_bind).
10. , ( main).
16
1. (port mapper) .
, poa rpcinf. , ,
, . TCP, RPC RST
SYN (, ),
clnt_create. UDP ( ),
-.
2. RPC , 20 .
,
RPC. , . ,
eaao . RPC ,
XID , XID .
3. char c[10], XDR 4- .
, .
4. xdr_data FALSE, xdr_string ( data_xdr.c) FALSE.
xdr_string. ,
0 (21 32- ).
5. opoa XDR FALSE
. , poa XDR .
6. , , TCP
, . (IP-
) 32- TCP, 2 2 .
7. ,
, . TI-RPC : (1) XID, (2) , (3)
, (4) , (5) . XID ,
.
8. . 16.5 4- , 4 long. 48 .
. 8 : 4
(AUTH_NONE) 4 (0).
( . 16.7, , TCP, 4 XID)
4- , long. 32 .
UDP (4 ). 44
, 28 , tcpdump.
9. . , . main
, main . RPC
RPC, , .
10. XDR (). , poae read:

printf(sbrk()=
in.vstring_arg);

%p,

buff

%p,

in.vstring_arg

%p\n",

sbrk(NULL),

buff,

sbrk , malloc
. , :

sbrk() = 29638, buff = 2548, in.vstring_arg = 27e58


, vstring_arg , mall. buff 8192 02548
02747, .
11. .11 -. , clnt_call timeval,
. , clnt_call XDR,
xdr_void (, ). ,
, RPC, , rpcgen
.

.11. ,

//sunrpc/square10/client.c
1 #include "unpipc.h" /* our header */
2 #include "square.h" /* generated by rpcgen */
3
4
5
6

int
main(int argc, char **argv)
{
CLIENT *cl;

316

7
struct timeval tv;
8
if (argc != 3)
9
err_quit("usage: client ");
10 cl = Clnt_create(argv[1], SQUARE_PROG, SQUARE_VERS, argv[2]);
11 tv.tv_sec = 10;
12 tv.tv_usec = 0;
13 if (clnt_call(cl, NULLPROC, xdr_void, NULL,
14
xdr_void, NULL, tv) != RPC_SUCCESS)
15 err_quit("%s", clnt_sperror(cl, argv[1]));
16 exit(0);
17 }
12. UDP (65536+20+ RPC) 65535
IPv4. . .2 Sun RPC UDP 16384 32768, RPCSRC 4.0
UDP 9000 .

, , , . ,
http://www.kohala.com/~rstevens.
1. Bach M.J. The Design of the UNIX Operating System //Prentice Hall, Englewood Cliffs, N.J., 1986.
2. Birrell A. D., Nelson B.J. Implementing Remote Procedure Calls //ACM Transactions on Computer Systems, vol. 2, no. 1, pp. 39-59 (Feb.), 1984.
3. Butenhorf D. R. Programming with POSIX Threads //Addison-Wesley, Reading, Mass, 1997.
4. Corbin J. R. The Art of Distributed Applications: Programming Techniques for Remote Procedure Calls //Springer-Verlag, New-York, 1991.
5. Garfinkel S. L, Spafford E. H. Practical UNIX and Internet Security, Second Edition //O'Reilly & Associates, Sebastopol, Calif, 1996.
6. Goodheart.,Cox J. The Magi Garden Explained: The Internals of UNIX System V Release 4, An Open Systems Design //Prentice Hall, Englewood Cliffs, N.J.,
1994.
7. Hamilton. G., Kougiouris P. The Spring Nucleus: A Mikrokernel for Objects // Proceedings of the 1993 Summer USENIX Conference, pp. 147-159, Cincinnati
Oh, 1993.
http://www.kohala.com/~rstevens/papers.others/springnucleus.1993.ps
8. IEEE 1996. Information Technology Portable Operating System Interface (POSIX) Part 1: System Application Program Interface (API) //IEEE Std 1003.1,
1996 Edition, Insitute of Electrical and Electonics Enibeers, Piscataway, N.J. (July).
Posix.1 ( ISO/IEC 9945-1: 1996) API (1990), 1003.1b
(1993), Pthreads 1003.1 (1995) 1003.1i (1995). , http://www.ieee.org.
, IEEE .
9. Josey A. Go Solo 2: The Authorized Guide to Version 2 of the Single UNIX Specification //Prentice Hall, Upper Saddle River, N. J., ed. 1997.
http://www.UNIX-systems.org/online.html Unix (, ).
10. Kernighan .W., Pike R. The UNIX Programming Environment //Prentice Hall, Englewood Cliffs, N. J., 1984.11.
11. Kernighan.W., Ritchie D. M. The Programming Language, Second Edition // Prentice Hall, Englewood Cliffs, N.J., 1988.
12. Kleiman S., Shah D., Smaalders B. Programming with Threads //Prentice Hall, Upper Saddle River, N. J., 1996.
13. Lewis., Berg D.J. Multithreaded Programming with Pthreads //Prentice Hall, Upper Saddle River, N. J., 1998.
14. McKusick M. K., Bostic K., Karels M.J., Quaterman J. S. The Design and Implementation of the 4.4BSD Operating System //Addison-Wesley, Reading, Mass,
1996.
15. McVoy L, Staelin . lmbench: Portable Tools for Performance Analysis //Proceedings of the 1996 Winter Technical Conference, pp. 279-294, San Diego,
Calif, 1996.
http:// www.bitmover.com/lmbench .
16. Rochkind M.J. Advanced UNIX Programming //Prentice Hall, Englewood Cliffs, N.J., 1985.
17. Salus P. H. A Quarter Century of Unix //Addison-Wesley, Reading, Mass, 1994.
18. Srinivasan R. RPC: Remote Procedure Call Protocol Specification Version 2 // RFC 1831, 18 pages (Aug.), 1995.
19. Srinivasan R. XDR: External Data Representation Standard //RFC 1832, 24 pages (Aug.), 1995.
20. Srinivasan R. Binding Protocols foe ONC RPC Version 2 //RFC 1833, 14 pages (Aug.), 1995.
21. Stevens W. R. Advanced Programming in the UNIX Environment //Addison-Wesley, Reading, Mass, 1992.
22. Stevens W. R. TCP/IP Illustrated, Volume 1: The Protocols //Addison-Wesley, Reading, Mass, 1994.
23. Stevens W. R. TCP/IP Illustrated, Volume 3: TCP for Transactions, HTTP, NNTP, and the UNIX Domain Protocols //Addison-Wesley, Reading, Mass, 1996.
24. Stevens W. R. UNIX Network Programming, Volume 1, Second Edition, Networking APIs: Sockets and XTI //Prentice Hall, Upper Saddle River, N.J., 1998.
25. Vahalia U. UNIX Internals: The New Frontiers //Prentice Hall, Upper Saddle River, N.J., 1996.
26. White J. E. A High-Level Framework for Network-Based Resource Sharing // RFC 707, 27 pages (Dec), 1975.
http://www.kohala.com/~rstevens/papers.others/rfc707.txt
27. Wright G. R., Stevens W. R. TCP/IP Illustrated, Volume 2: The Implementation // Addison-Wesley, Reading, Mass, 1995.

317