introduce struct audio_format_info
[paraslash.git] / ipc.c
1 /*
2  * Copyright (C) 2006-2007 Andre Noll <maan@systemlinux.org>
3  *
4  *     This program is free software; you can redistribute it and/or modify
5  *     it under the terms of the GNU General Public License as published by
6  *     the Free Software Foundation; either version 2 of the License, or
7  *     (at your option) any later version.
8  *
9  *     This program is distributed in the hope that it will be useful,
10  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *     GNU General Public License for more details.
13  *
14  *     You should have received a copy of the GNU General Public License
15  *     along with this program; if not, write to the Free Software
16  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17  */
18
19 /** \file ipc.c interprocess communication and shared memory helpers */
20
21 #include "para.h"
22 #include "error.h"
23 #include "ipc.h"
24 #include <sys/ipc.h>
25 #include <sys/shm.h>
26 #include <sys/sem.h>
27
28 /** abort if semget() failed that many times */
29 #define MAX_SEMOP_RETRIES 500
30
31 /**
32  * define a new mutex
33  *
34  * \return the identifier for the new mutex on success, \a -E_SEM_GET
35  * on errors.
36  *
37  * \sa semget(2)
38  */
39 int mutex_new(void)
40 {
41         int ret = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
42         return ret < 0?  -E_SEM_GET : ret;
43 }
44
45 /**
46  * destroy a mutex
47  *
48  * \param id the identifier of the mutex to be destroyed
49  *
50  * \return Positive on success, \a -E_SEM_REMOVE on errors.
51  *
52  * \sa semctl(2)
53  */
54 int mutex_destroy(int id)
55 {
56         int ret = semctl(id, 0, IPC_RMID);
57         return ret < 0? -E_SEM_REMOVE : 1;
58 }
59
60 static void para_semop(int id, struct sembuf *sops, int num)
61 {
62         int i;
63
64         for (i = 0; i < MAX_SEMOP_RETRIES; i++)
65                 if (semop(id, sops, num) >= 0)
66                         return;
67         PARA_EMERG_LOG("semop failed %d times, aborting\n", MAX_SEMOP_RETRIES);
68         exit(EXIT_FAILURE);
69 }
70
71 /**
72  * lock the given mutex
73  *
74  * \param id of the shared memory area to lock
75  *
76  * This function either succeeds or aborts.
77  *
78  * \sa semop(2), struct misc_meta_data
79  */
80 void mutex_lock(int id)
81 {
82         struct sembuf sops[2] = {
83                 {
84                         .sem_num = 0,
85                         .sem_op = 0,
86                         .sem_flg = SEM_UNDO
87                 },
88                 {
89                         .sem_num = 0,
90                         .sem_op = 1,
91                         .sem_flg = SEM_UNDO
92                 }
93         };
94         para_semop(id, sops, 2);
95 }
96
97 /**
98  * unlock a mutex
99  *
100  * \param id the identifier of the mutex
101  *
102  * This function either succeeds or aborts.
103  *
104  * \sa semop(2), struct misc_meta_data
105  */
106 void mutex_unlock(int id)
107 {
108         struct sembuf sops[1] = {
109                 {
110                         .sem_num = 0,
111                         .sem_op = -1,
112                         .sem_flg = SEM_UNDO
113                 },
114         };
115         para_semop(id, sops, 1);
116 }
117
118 /**
119  * create a new shared memory area of given size
120  *
121  * \param size the size of the shared memory area to create
122  *
123  * \return The id of the shared memory areay on success, \a -E_SHM_GET on errors.
124  *
125  * \sa shmget(2)
126  */
127 int shm_new(size_t size)
128 {
129         int ret = shmget(IPC_PRIVATE, size, IPC_CREAT | IPC_EXCL | 0600);
130         return ret < 0 ? -E_SHM_GET : ret;
131 }
132
133 /**
134  * destroy the given shared memory area
135  *
136  * \param id the shared memory id
137  *
138  * \return The return value of the underlying shmctl() call on success,
139  * \a -E_SHM_DESTROY on errors.
140  *
141  * \sa shmctl(2)
142  */
143 int shm_destroy(int id)
144 {
145         struct shmid_ds shm_desc;
146         int ret = shmctl(id, IPC_RMID, &shm_desc);
147         return ret < 0? -E_SHM_DESTROY : ret;
148 }
149
150 /**
151  * attach a shared memory segment
152  *
153  * \param id the identifier of the shared memory segment to attach
154  * \param mode either ATTACH_RO (read only) or ATTACH_RW (read/write)
155  * \param result points to the attached area just attached
156  *
157  * \return positive on success, \a -E_SHM_ATTACH on errors.
158  *
159  * \sa shmat(2)
160  */
161 int shm_attach(int id, enum shm_attach_mode mode, void **result)
162 {
163         if (mode == ATTACH_RW) {
164                 *result = shmat(id, NULL, 0);
165                 return *result? 1 : -E_SHM_ATTACH;
166         }
167         *result = shmat(id, NULL, SHM_RDONLY);
168         return *result? 1 : -E_SHM_ATTACH;
169 }
170
171 /**
172  * detach a shared memory segment
173  *
174  * \param addr the address of the attached segment
175  *
176  * \return positive on success, \a -E_SHM_DETACH on errors.
177  *
178  * \sa shmdt(2)
179  */
180 int shm_detach(void *addr)
181 {
182         int ret = shmdt(addr);
183         return ret < 0? -E_SHM_DETACH : 1;
184 }