1
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
/*
* Copyright (C) 2006-2009 Andre Noll <maan@systemlinux.org>
*
* Licensed under the GPL v2. For licencing details see COPYING.
*/
/** \file ipc.c Inter-process communication and shared memory helpers. */
#include "para.h"
#include "error.h"
#include "ipc.h"
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
/**
* Define a new mutex.
*
* \return The identifier for the new mutex on success, a negative error code
* on errors.
*
* \sa semget(2).
*/
int mutex_new(void)
{
int ret = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
return ret < 0? -ERRNO_TO_PARA_ERROR(errno) : ret;
}
/**
* Destroy a mutex.
*
* \param id The identifier of the mutex to be destroyed.
*
* \return Standard.
*
* \sa semctl(2)
*/
int mutex_destroy(int id)
{
int ret = semctl(id, 0, IPC_RMID);
return ret < 0? -ERRNO_TO_PARA_ERROR(errno) : 1;
}
static void para_semop(int id, struct sembuf *sops, int num)
{
do {
if (semop(id, sops, num) >= 0)
return;
} while (errno == EINTR);
if (errno == EIDRM) {
PARA_CRIT_LOG("semaphore set %d was removed\n", id);
return;
}
PARA_EMERG_LOG("fatal semop error %s: pid %d\n", strerror(errno),
(int)getpid());
exit(EXIT_FAILURE);
}
/**
* Lock the given mutex.
*
* \param id The identifier of the shared memory area to lock.
*
* This function either succeeds or aborts.
*
* \sa semop(2), struct misc_meta_data.
*/
void mutex_lock(int id)
{
struct sembuf sops[2] = {
{
.sem_num = 0,
.sem_op = 0,
.sem_flg = SEM_UNDO
},
{
.sem_num = 0,
.sem_op = 1,
.sem_flg = SEM_UNDO
}
};
para_semop(id, sops, 2);
}
/**
* Unlock a mutex.
*
* \param id The identifier of the mutex.
*
* This function either succeeds or aborts.
*
* \sa semop(2), struct misc_meta_data.
*/
void mutex_unlock(int id)
{
struct sembuf sops[1] = {
{
.sem_num = 0,
.sem_op = -1,
.sem_flg = SEM_UNDO
},
};
para_semop(id, sops, 1);
}
/**
* Create a new shared memory area of given size.
*
* \param size The size of the shared memory area to create.
*
* \return The id of the shared memory array on success, a negative error
* code on errors.
*
* \sa shmget(2).
*/
int shm_new(size_t size)
{
int ret = shmget(IPC_PRIVATE, size, IPC_CREAT | IPC_EXCL | 0600);
return ret < 0 ? -ERRNO_TO_PARA_ERROR(errno) : ret;
}
/**
* Destroy the given shared memory area.
*
* \param id The shared memory identifier.
*
* \return The return value of the underlying shmctl() call on success,
* a negative error code on errors.
*
* \sa shmctl(2).
*/
int shm_destroy(int id)
{
struct shmid_ds shm_desc;
int ret = shmctl(id, IPC_RMID, &shm_desc);
return ret < 0? -ERRNO_TO_PARA_ERROR(errno) : ret;
}
/**
* Attach a shared memory segment.
*
* \param id The identifier of the shared memory segment to attach.
* \param mode Either ATTACH_RO (read only) or ATTACH_RW (read/write).
* \param result Points to the attached area just attached on success.
*
* \return Standard.
*
* \sa shmat(2).
*/
int shm_attach(int id, enum shm_attach_mode mode, void **result)
{
if (mode == ATTACH_RW)
*result = shmat(id, NULL, 0);
else
*result = shmat(id, NULL, SHM_RDONLY);
return *result == (void *) -1? -ERRNO_TO_PARA_ERROR(errno) : 1;
}
/**
* Detach a shared memory segment.
*
* \param addr The address of the attached segment.
*
* \return Standard.
*
* \sa shmdt(2).
*/
int shm_detach(void *addr)
{
int ret = shmdt(addr);
return ret < 0? -ERRNO_TO_PARA_ERROR(errno) : 1;
}
|