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