root/trunk/libffado/src/libutil/PosixSharedMemory.cpp

Revision 1172, 8.1 kB (checked in by ppalmers, 13 years ago)

lay down the foundations for easy ALSA/Pulse support

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "PosixSharedMemory.h"
25
26 #include <sys/mman.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <fcntl.h>
30
31 namespace Util {
32
33 IMPL_DEBUG_MODULE( PosixSharedMemory, PosixSharedMemory, DEBUG_LEVEL_NORMAL );
34
35 PosixSharedMemory::PosixSharedMemory(std::string name, unsigned int size)
36 : m_name( "/" + name )
37 , m_size( size )
38 , m_owner( false )
39 , m_access( NULL )
40 {
41
42 }
43
44 PosixSharedMemory::~PosixSharedMemory()
45 {
46     debugOutput(DEBUG_LEVEL_VERBOSE,
47                 "(%p, %s) destroy\n",
48                 this, m_name.c_str());
49     Close();
50     if(m_owner) {
51         debugOutput(DEBUG_LEVEL_VERBOSE,
52                     "(%p, %s) unlink\n",
53                     this, m_name.c_str());
54         shm_unlink(m_name.c_str());
55     }
56 }
57
58 bool
59 PosixSharedMemory::Open(enum eDirection d)
60 {
61     debugOutput(DEBUG_LEVEL_VERBOSE,
62                 "(%p, %s) open\n",
63                 this, m_name.c_str());
64     if(m_access != NULL) {
65         debugError("(%p, %s) already attached to segment\n", this, m_name.c_str());
66     }
67
68     int flags=0;
69     switch(d) {
70         case eD_ReadOnly: flags |= O_RDONLY; break;
71         case eD_WriteOnly: flags |= O_WRONLY; break;
72         case eD_ReadWrite: flags |= O_RDWR; break;
73         default:
74             debugError("bad direction\n");
75             return false;
76     }
77
78     // open the shared memory segment
79     int fd = shm_open(m_name.c_str(), flags, S_IRWXU);
80     if (fd < 0) {
81         if (errno != ENOENT) {
82             debugError("(%p, %s) Cannot open shared memory: %s\n",
83                        this, m_name.c_str(), strerror (errno));
84         } else {
85             debugError("(%p, %s) shared memory segment does not exist: %s\n",
86                        this, m_name.c_str(), strerror (errno));
87         }
88         close(fd);
89         return false;
90     }
91
92     // mmap the memory
93     flags=0;
94     switch(d) {
95         case eD_ReadOnly: flags |= PROT_READ; break;
96         case eD_WriteOnly: flags |= PROT_WRITE; break;
97         case eD_ReadWrite: flags |= PROT_READ|PROT_WRITE; break;
98         default:
99             debugError("bad direction\n");
100             shm_unlink(m_name.c_str());
101             return false;
102     }
103
104     m_access = (char*)mmap(0, m_size, flags, MAP_SHARED, fd, 0);
105     if (m_access == MAP_FAILED) {
106         debugError("(%p, %s) Cannot mmap shared memory: %s\n",
107                     this, m_name.c_str(), strerror (errno));
108         close(fd);
109         m_access = NULL;
110         shm_unlink(m_name.c_str());
111         return false;
112     }
113
114     // close the fd
115     close(fd);
116     return true;
117 }
118
119 bool
120 PosixSharedMemory::Create(enum eDirection d)
121 {
122     debugOutput(DEBUG_LEVEL_VERBOSE,
123                 "(%p, %s) create dir: %d, size: %u \n",
124                 this, m_name.c_str(), d, m_size);
125     if(m_access != NULL) {
126         debugError("(%p, %s) already attached to segment\n", this, m_name.c_str());
127     }
128
129     // open the shared memory segment
130     // always create it readwrite, if not, the other side can't map
131     // it correctly, nor can we truncate it to the right length.
132     int fd = shm_open(m_name.c_str(), O_RDWR|O_CREAT, S_IRWXU);
133     if (fd < 0) {
134         debugError("(%p, %s) Cannot open shared memory: %s\n",
135                     this, m_name.c_str(), strerror (errno));
136         close(fd);
137         return false;
138     }
139
140     // set size
141     if (ftruncate (fd, m_size) < 0) {
142         debugError("(%p, %s) Cannot set shared memory size: %s\n",
143                     this, m_name.c_str(), strerror (errno));
144         close(fd);
145         return false;
146     }
147
148     // mmap the memory
149     int flags=0;
150     switch(d) {
151         case eD_ReadOnly: flags |= PROT_READ; break;
152         case eD_WriteOnly: flags |= PROT_WRITE; break;
153         case eD_ReadWrite: flags |= PROT_READ|PROT_WRITE; break;
154         default:
155             debugError("bad direction\n");
156             return false;
157     }
158
159     m_access = (char*)mmap(0, m_size, flags, MAP_SHARED, fd, 0);
160     if (m_access == MAP_FAILED) {
161         debugError("(%p, %s) Cannot mmap shared memory: %s\n",
162                     this, m_name.c_str(), strerror (errno));
163         close(fd);
164         m_access = NULL;
165         return false;
166     }
167
168     // close the fd
169     close(fd);
170
171     m_owner = true;
172     return true;
173 }
174
175 bool
176 PosixSharedMemory::Close()
177 {
178     debugOutput(DEBUG_LEVEL_VERBOSE,
179                 "(%p, %s) close\n",
180                 this, m_name.c_str());
181     if(m_access) {
182         if(munmap(m_access, m_size)) {
183             debugError("(%p, %s) Cannot munmap shared memory: %s\n",
184                        this, m_name.c_str(), strerror (errno));
185             return false;
186         }
187         m_access = NULL;
188     } else {
189         debugOutput(DEBUG_LEVEL_VERBOSE,
190                     "(%p, %s) not open\n",
191                     this, m_name.c_str());
192     }
193     return true;
194 }
195
196 enum PosixSharedMemory::eResult
197 PosixSharedMemory::Write(unsigned int offset, void * buff, unsigned int len)
198 {
199     debugOutput(DEBUG_LEVEL_VERBOSE,
200                 "(%p, %s) write\n",
201                 this, m_name.c_str());
202     if(offset+len <= m_size) {
203         char * addr = m_access + offset;
204         memcpy(addr, buff, len);
205         // if(msync(addr, len, MS_SYNC | MS_INVALIDATE)) {
206         //     debugError("Could not sync written block\n");
207         //     return eR_Error;
208         // }
209         return eR_OK;
210     } else {
211         debugError("Requested block (%u) out of range (%u)\n", offset+len, m_size);
212         return eR_Error;
213     }
214 }
215
216 enum PosixSharedMemory::eResult
217 PosixSharedMemory::Read(unsigned int offset, void * buff, unsigned int len)
218 {
219     debugOutput(DEBUG_LEVEL_VERBOSE,
220                 "(%p, %s) read\n",
221                 this, m_name.c_str());
222     if(offset+len <= m_size) {
223         char * addr = m_access + offset;
224         memcpy(buff, addr, len);
225         return eR_OK;
226     } else {
227         debugError("Requested block (%u) out of range (%u)\n", offset+len, m_size);
228         return eR_Error;
229     }
230 }
231
232 void*
233 PosixSharedMemory::requestBlock(unsigned int offset, unsigned int len)
234 {
235     debugOutput(DEBUG_LEVEL_VERBOSE,
236                 "(%p, %s) getBlock\n",
237                 this, m_name.c_str());
238     if(offset+len <= m_size) {
239         return (void*)(m_access + offset);
240     } else {
241         debugError("Requested block (%u) out of range (%u)\n", offset+len, m_size);
242         return NULL;
243     }
244 }
245
246 void
247 PosixSharedMemory::commitBlock(unsigned int offset, unsigned int len)
248 {
249     debugOutput(DEBUG_LEVEL_VERBOSE,
250                 "(%p, %s) commitBlock\n",
251                 this, m_name.c_str());
252     if(offset+len >= m_size) {
253         debugError("Committed block (%u) out of range (%u)\n", offset+len, m_size);
254     }
255 }
256
257 bool
258 PosixSharedMemory::LockInMemory(bool lock)
259 {
260     debugOutput(DEBUG_LEVEL_VERBOSE,
261                 "(%p, %s) LockInMemory\n",
262                 this, m_name.c_str());
263     if(lock) {
264         if(mlock(m_access, m_size)) {
265             debugError("(%p, %s) Cannot mlock shared memory: %s\n",
266                        this, m_name.c_str(), strerror (errno));
267             return false;
268         } else return true;
269     } else {
270         if(munlock(m_access, m_size)) {
271             debugError("(%p, %s) Cannot munlock shared memory: %s\n",
272                        this, m_name.c_str(), strerror (errno));
273             return false;
274         } else return true;
275     }
276     return false;
277 }
278
279 void
280 PosixSharedMemory::show()
281 {
282     debugOutput(DEBUG_LEVEL_NORMAL, "(%p) PosixSharedMemory %s\n", this, m_name.c_str());
283 }
284
285 } // namespace Util
Note: See TracBrowser for help on using the browser.