]> code.delx.au - pulseaudio/blob - src/pulsecore/shm.c
Huge trailing whitespace cleanup. Let's keep the tree pure from here on,
[pulseaudio] / src / pulsecore / shm.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <sys/stat.h>
34
35 #ifdef HAVE_SYS_MMAN_H
36 #include <sys/mman.h>
37 #endif
38
39 #include <pulsecore/core-error.h>
40 #include <pulsecore/log.h>
41 #include <pulsecore/random.h>
42 #include <pulse/xmalloc.h>
43
44 #include "shm.h"
45
46 #if defined(__linux__) && !defined(MADV_REMOVE)
47 #define MADV_REMOVE 9
48 #endif
49
50 #define MAX_SHM_SIZE (1024*1024*20)
51
52 static char *segment_name(char *fn, size_t l, unsigned id) {
53 snprintf(fn, l, "/pulse-shm-%u", id);
54 return fn;
55 }
56
57 int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) {
58 char fn[32];
59 int fd = -1;
60
61 assert(m);
62 assert(size > 0);
63 assert(size < MAX_SHM_SIZE);
64 assert(mode >= 0600);
65
66 if (!shared) {
67 m->id = 0;
68 m->size = size;
69
70 #ifdef MAP_ANONYMOUS
71 if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
72 pa_log("mmap() failed: %s", pa_cstrerror(errno));
73 goto fail;
74 }
75 #elif defined(HAVE_POSIX_MEMALIGN)
76 {
77 int r;
78
79 if ((r = posix_memalign(&m->ptr, sysconf(_SC_PAGESIZE), size)) < 0) {
80 pa_log("posix_memalign() failed: %s", pa_cstrerror(r));
81 goto fail;
82 }
83 }
84 #else
85 m->ptr = pa_xmalloc(m->size);
86 #endif
87
88 m->do_unlink = 0;
89
90 } else {
91 #ifdef HAVE_SHM_OPEN
92 pa_random(&m->id, sizeof(m->id));
93 segment_name(fn, sizeof(fn), m->id);
94
95 if ((fd = shm_open(fn, O_RDWR|O_CREAT|O_EXCL, mode & 0444)) < 0) {
96 pa_log("shm_open() failed: %s", pa_cstrerror(errno));
97 goto fail;
98 }
99
100 if (ftruncate(fd, m->size = size) < 0) {
101 pa_log("ftruncate() failed: %s", pa_cstrerror(errno));
102 goto fail;
103 }
104
105 if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
106 pa_log("mmap() failed: %s", pa_cstrerror(errno));
107 goto fail;
108 }
109
110 close(fd);
111 m->do_unlink = 1;
112 #else
113 return -1;
114 #endif
115 }
116
117 m->shared = shared;
118
119 return 0;
120
121 fail:
122
123 #ifdef HAVE_SHM_OPEN
124 if (fd >= 0) {
125 shm_unlink(fn);
126 close(fd);
127 }
128 #endif
129
130 return -1;
131 }
132
133 void pa_shm_free(pa_shm *m) {
134 assert(m);
135 assert(m->ptr);
136 assert(m->size > 0);
137
138 #ifdef MAP_FAILED
139 assert(m->ptr != MAP_FAILED);
140 #endif
141
142 if (!m->shared) {
143 #ifdef MAP_ANONYMOUS
144 if (munmap(m->ptr, m->size) < 0)
145 pa_log("munmap() failed: %s", pa_cstrerror(errno));
146 #elif defined(HAVE_POSIX_MEMALIGN)
147 free(m->ptr);
148 #else
149 pa_xfree(m->ptr);
150 #endif
151 } else {
152 #ifdef HAVE_SHM_OPEN
153 if (munmap(m->ptr, m->size) < 0)
154 pa_log("munmap() failed: %s", pa_cstrerror(errno));
155
156 if (m->do_unlink) {
157 char fn[32];
158
159 segment_name(fn, sizeof(fn), m->id);
160
161 if (shm_unlink(fn) < 0)
162 pa_log(" shm_unlink(%s) failed: %s", fn, pa_cstrerror(errno));
163 }
164 #else
165 /* We shouldn't be here without shm support */
166 assert(0);
167 #endif
168 }
169
170 memset(m, 0, sizeof(*m));
171 }
172
173 void pa_shm_punch(pa_shm *m, size_t offset, size_t size) {
174 void *ptr;
175
176 assert(m);
177 assert(m->ptr);
178 assert(m->size > 0);
179 assert(offset+size <= m->size);
180
181 #ifdef MAP_FAILED
182 assert(m->ptr != MAP_FAILED);
183 #endif
184
185 /* You're welcome to implement this as NOOP on systems that don't
186 * support it */
187
188 ptr = (uint8_t*) m->ptr + offset;
189
190 #ifdef __linux__
191 {
192 /* On Linux ptr must be page aligned */
193 long psz = sysconf(_SC_PAGESIZE);
194 unsigned o;
195
196 o = ((unsigned long) ptr) - ((((unsigned long) ptr)/psz) * psz);
197
198 if (o > 0) {
199 ptr = (uint8_t*) ptr + (psz - o);
200 size -= psz - o;
201 }
202 }
203 #endif
204
205 #ifdef MADV_REMOVE
206 if (madvise(ptr, size, MADV_REMOVE) >= 0)
207 return;
208 #endif
209
210 #ifdef MADV_FREE
211 if (madvise(ptr, size, MADV_FREE) >= 0)
212 return;
213 #endif
214
215 #ifdef MADV_DONTNEED
216 madvise(ptr, size, MADV_DONTNEED);
217 #endif
218 }
219
220 #ifdef HAVE_SHM_OPEN
221
222 int pa_shm_attach_ro(pa_shm *m, unsigned id) {
223 char fn[32];
224 int fd = -1;
225 struct stat st;
226
227 assert(m);
228
229 segment_name(fn, sizeof(fn), m->id = id);
230
231 if ((fd = shm_open(fn, O_RDONLY, 0)) < 0) {
232 pa_log("shm_open() failed: %s", pa_cstrerror(errno));
233 goto fail;
234 }
235
236 if (fstat(fd, &st) < 0) {
237 pa_log("fstat() failed: %s", pa_cstrerror(errno));
238 goto fail;
239 }
240
241 if (st.st_size <= 0 || st.st_size > MAX_SHM_SIZE) {
242 pa_log("Invalid shared memory segment size");
243 goto fail;
244 }
245
246 m->size = st.st_size;
247
248 if ((m->ptr = mmap(NULL, m->size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
249 pa_log("mmap() failed: %s", pa_cstrerror(errno));
250 goto fail;
251 }
252
253 m->do_unlink = 0;
254 m->shared = 1;
255
256 close(fd);
257
258 return 0;
259
260 fail:
261 if (fd >= 0)
262 close(fd);
263
264 return -1;
265 }
266
267 #else /* HAVE_SHM_OPEN */
268
269 int pa_shm_attach_ro(pa_shm *m, unsigned id) {
270 return -1;
271 }
272
273 #endif /* HAVE_SHM_OPEN */