/*
* Provide an simpler and easier to understand interface to the System V
* semaphore system calls. There are 7 routines available to the user:
*
* id = sem_create(key, initval); # create with initial value or open
* id = sem_open(key); # open (must already exist)
* sem_wait(id); # wait = P = down by 1
* sem_signal(id); # signal = V = up by 1
* sem_op(id, amount); # wait if (amount < 0)
* # signal if (amount > 0)
* sem_close(id); # close
* sem_rm(id); # remove (delete)
*
* We create and use a 3-member set for the requested semaphore.
* The first member, [0], is the actual semaphore value, and the second
* member, [1], is a counter used to know when all processes have finished
* with the semaphore. The counter is initialized to a large number,
* decremented on every create or open and incremented on every close.
* This way we can use the "adjust" feature provided by System V so that
* any process that exit's without calling sem_close() is accounted
* for. It doesn't help us if the last process does this (as we have
* no way of getting control to remove the semaphore) but it will
* work if any process other than the last does an exit (intentional
* or unintentional).
* The third member, [2], of the semaphore set is used as a lock variable
* to avoid any race conditions in the sem_create() and sem_close()
* functions.
*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include "ourhdr.h"
void sem_op(int, int);
int sem_create(key_t, int);
int sem_open(key_t);
void sem_rm(int);
void sem_close(int);
void sem_wait(int);
void sem_signal(int);
#define BIGCOUNT 10000 /* initial value of process counter */
/*
* Define the semaphore operation arrays for the semop() calls.
*/
static struct sembuf op_lock[2] = {
2, 0, 0, /* wait for [2] (lock) to equal 0 */
2, 1, SEM_UNDO /* then increment [2] to 1 - this locks it */
/* UNDO to release the lock if processes exits
before explicitly unlocking */
};
static struct sembuf op_endcreate[2] = {
1, -1, SEM_UNDO,/* decrement [1] (proc counter) with undo on exit */
/* UNDO to adjust proc counter if process exits
before explicitly calling sem_close() */
2, -1, SEM_UNDO /* then decrement [2] (lock) back to 0 */
};
static struct sembuf op_open[1] = {
1, -1, SEM_UNDO /* decrement [1] (proc counter) with undo on exit */
};
static struct sembuf op_close[3] = {
2, 0, 0, /* wait for [2] (lock) to equal 0 */
2, 1, SEM_UNDO, /* then increment [2] to 1 - this locks it */
1, 1, SEM_UNDO /* then increment [1] (proc counter) */
};
static struct sembuf op_unlock[1] = {
2, -1, SEM_UNDO /* decrement [2] (lock) back to 0 */
};
static struct sembuf op_op[1] = {
0, 99, SEM_UNDO /* decrement or increment [0] with undo on exit */
/* the 99 is set to the actual amount to add
or subtract (positive or negative) */
};
/****************************************************************************
* Create a semaphore with a specified initial value.
* If the semaphore already exists, we don't initialize it (of course).
* We return the semaphore ID if all OK, else -1.
*/
int
sem_create(key_t key, int initval)
{
register int id, semval;
union semun {
int val;
struct semid_ds *buf;
ushort *array;
} semctl_arg;
if (key == IPC_PRIVATE)
return(-1); /* not intended for private semaphores */
else if (key == (key_t) -1)
return(-1); /* probably an ftok() error by caller */
again:
if ( (id = semget(key, 3, 0666 | IPC_CREAT)) < 0)
return(-1); /* permission problem or tables full */
/*
* When the semaphore is created, we know that the value of all
* 3 members is 0.
* Get a lock on the semaphore by waiting for [2] to equal 0,
* then increment it.
*
* There is a race condition here. There is a possibility that
* between the semget() above and the semop() below, another
* process can call our sem_close() function which can remove
* the semaphore if that process is the last one using it.
* Therefore, we handle the error condition of an invalid
* semaphore ID specially below, and if it does happen, we just
* go back and create it again.
*/
if (semop(id, &op_lock[0], 2) < 0) {
if (errno == EINVAL)
goto again;
err_sys("can't lock");
}
/*
* Get the value of the process counter. If it equals 0,
* then no one has initialized the semaphore yet.
*/
if ( (semval = semctl(id, 1, GETVAL, 0)) < 0)
err_sys("can't GETVAL");
if (semval == 0) {
/*
* We could initialize by doing a SETALL, but that
* would clear the adjust value that we set when we
* locked the semaphore above. Instead, we'll do 2
* system calls to initialize [0] and [1].
*/
semctl_arg.val = initval;
if (semctl(id, 0, SETVAL, semctl_arg) < 0)
err_sys("can SETVAL[0]");
semctl_arg.val = BIGCOUNT;
if (semctl(id, 1, SETVAL, semctl_arg) < 0)
err_sys("can SETVAL[1]");
}
/*
* Decrement the process counter and then release the lock.
*/
if (semop(id, &op_endcreate[0], 2) < 0)
err_sys("can't end create");
return(id);
}
/****************************************************************************
* Open a semaphore that must already exist.
* This function should be used, instead of sem_create(), if the caller
* knows that the semaphore must already exist. For example a client
* from a client-server pair would use this, if its the server's
* responsibility to create the semaphore.
* We return the semaphore ID if all OK, else -1.
*/
int
sem_open(key_t key)
{
register int id;
if (key == IPC_PRIVATE)
return(-1); /* not intended for private semaphores */
else if (key == (key_t) -1)
return(-1); /* probably an ftok() error by caller */
if ( (id = semget(key, 3, 0)) < 0)
return(-1); /* doesn't exist, or tables full */
/*
* Decrement the process counter. We don't need a lock
* to do this.
*/
if (semop(id, &op_open[0], 1) < 0)
err_sys("can't open");
return(id);
}
/****************************************************************************
* Remove a semaphore.
* This call is intended to be called by a server, for example,
* when it is being shut down, as we do an IPC_RMID on the semaphore,
* regardless whether other processes may be using it or not.
* Most other processes should use sem_close() below.
*/
void
sem_rm(int id)
{
if (semctl(id, 0, IPC_RMID, 0) < 0)
err_sys("can't IPC_RMID");
}
/****************************************************************************
* Close a semaphore.
* Unlike the remove function above, this function is for a process
* to call before it exits, when it is done with the semaphore.
* We "decrement" the counter of processes using the semaphore, and
* if this was the last one, we can remove the semaphore.
*/
void
sem_close(int id)
{
register int semval;
/*
* The following semop() first gets a lock on the semaphore,
* then increments [1] - the process counter.
*/
if (semop(id, &op_close[0], 3) < 0)
err_sys("can't semop");
/*
* Now that we have a lock, read the value of the process
* counter to see if this is the last reference to the
* semaphore.
* There is a race condition here - see the comments in
* sem_create().
*/
if ( (semval = semctl(id, 1, GETVAL, 0)) < 0)
err_sys("can't GETVAL");
if (semval > BIGCOUNT)
err_dump("sem[1] > BIGCOUNT");
else if (semval == BIGCOUNT)
sem_rm(id);
else
if (semop(id, &op_unlock[0], 1) < 0)
err_sys("can't unlock"); /* unlock */
}
/****************************************************************************
* Wait until a semaphore's value is greater than 0, then decrement
* it by 1 and return.
* Dijkstra's P operation. Tanenbaum's DOWN operation.
*/
void
sem_wait(int id)
{
sem_op(id, -1);
}
/****************************************************************************
* Increment a semaphore by 1.
* Dijkstra's V operation. Tanenbaum's UP operation.
*/
void
sem_signal(int id)
{
sem_op(id, 1);
}
/********
没有合适的资源?快使用搜索试试~ 我知道了~
apue.rar_apue_apue pudn
共414个文件
c:330个
h:36个
makefile:27个
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 147 浏览量
2022-09-19
13:57:55
上传
评论
收藏 243KB RAR 举报
温馨提示
apue第二版每一章节的c语言源码,很不错的学习
资源推荐
资源详情
资源评论
收起资源包目录
apue.rar_apue_apue pudn (414个子文件)
Make.def.44 708B
acctfile 23B
awkexample 98B
semaph.c 8KB
semaph.c 8KB
semaph.c 8KB
semaph.c 8KB
loop.c 5KB
ftw4.c 4KB
store.c 3KB
input.c 3KB
message.c 3KB
main.c 3KB
ttyopen.c 3KB
readidx.c 3KB
expectstr.c 2KB
tty.c 2KB
popen.c 2KB
popen.c 2KB
popen.c 2KB
popen.c 2KB
recvfd.c 2KB
recvfd.c 2KB
open.c 2KB
ttymodes.c 2KB
ttymodes.c 2KB
ttymodes.c 2KB
ttymodes.c 2KB
lock.c 2KB
errorlog.c 2KB
errorlog.c 2KB
errorlog.c 2KB
errorlog.c 2KB
conf.c 2KB
take.c 2KB
ptyfork.c 2KB
ptyfork.c 2KB
ptyfork.c 2KB
ptyfork.c 2KB
output.c 2KB
error.c 2KB
error.c 2KB
error.c 2KB
error.c 2KB
loop.c 2KB
dodelete.c 2KB
recvfd.c 2KB
request.c 2KB
devfile.c 2KB
cliconn.c 2KB
sysfile.c 2KB
sendstr.c 2KB
atexit.c 2KB
servaccept.c 2KB
client.c 2KB
writeidx.c 2KB
find.c 2KB
servaccept.c 2KB
childdial.c 2KB
servaccept.c 2KB
cliconn.c 2KB
loop.poll.c 2KB
system.c 2KB
loop.poll.c 2KB
loop.c 2KB
loop.c 2KB
loop.select.c 2KB
cliconn.c 2KB
pathconf.c 1KB
pathconf.c 1KB
times1.c 1KB
recvfd.c 1KB
mandatory.c 1KB
dialfile.c 1KB
mail.c 1KB
pipe2.c 1KB
sendfd.c 1KB
sendfd.c 1KB
findfree.c 1KB
pipe4.c 1KB
put.c 1KB
open.c 1KB
tellwait.c 1KB
tellwait.c 1KB
tellwait.c 1KB
tellwait.c 1KB
main.c 1KB
client.c 1KB
main.c 1KB
spipe4.c 1KB
mcopy.c 1KB
ptyopen.c 1KB
ptyopen.c 1KB
ptyopen.c 1KB
pracct.c 1KB
escape.c 1KB
ptyopen.c 1KB
getpass.c 1KB
takeput.c 1KB
devzero.c 1KB
共 414 条
- 1
- 2
- 3
- 4
- 5
资源评论
钱亚锋
- 粉丝: 86
- 资源: 1万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功