Plug more leaks (in the test, not the core)
[gnash.git] / libbase / SharedMem.cpp
blobd339fc467852d5e30d8f08dd98c78b1eb9ef1df0
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
3 // Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
23 #include "SharedMem.h"
25 #include <string>
26 #include <vector>
27 #include <cerrno>
28 #include <cstring>
30 #if !defined(__riscos__) && !defined(__OS2__)
31 # include <sys/types.h>
32 # include <sys/shm.h>
33 # include <sys/sem.h>
34 # include <sys/ipc.h>
35 #endif
37 #include "log.h"
39 #if (defined(USE_SYSV_SHM) && defined(HAVE_SHMGET))
40 # define ENABLE_SHARED_MEM 1
41 #else
42 # undef ENABLE_SHARED_MEM
43 #endif
45 namespace {
46 gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
49 namespace gnash {
51 SharedMem::SharedMem(size_t size)
53 _addr(0),
54 _size(size),
55 _semid(0),
56 _shmid(0),
57 _shmkey(0)
61 SharedMem::~SharedMem()
63 // Nothing to do if we were never attached.
64 if (!_addr) return;
66 if (::shmdt(_addr) < 0) {
67 const int err = errno;
68 log_error("Error detaching shared memory: %s", std::strerror(err));
71 // We can still try to shut it down.
72 struct ::shmid_ds ds;
73 if (::shmctl(_shmid, IPC_STAT, &ds) < 0) {
74 const int err = errno;
75 log_error("Error during stat of shared memory segment: %s",
76 std::strerror(err));
79 #ifndef __amigaos4__
80 else {
81 // Note that this isn't completely reliable.
82 if (!ds.shm_nattch) {
83 log_debug("No shared memory users left. Removing segment.");
84 ::shmctl(_shmid, IPC_RMID, 0);
87 #endif
90 bool
91 SharedMem::lock() const
93 struct sembuf sb = { 0, -1, SEM_UNDO };
94 const int ret = ::semop(_semid, &sb, 1);
95 return ret >= 0;
98 bool
99 SharedMem::unlock() const
101 struct sembuf sb = { 0, 1, SEM_UNDO };
102 const int ret = ::semop(_semid, &sb, 1);
103 return ret >= 0;
106 bool
107 SharedMem::attach()
109 #if !ENABLE_SHARED_MEM
110 # error "You need SYSV Shared memory support to use this option"
111 #endif
113 // Don't try to attach twice.
114 if (_addr) return true;
116 _shmkey = rcfile.getLCShmKey();
118 // Check rcfile for key; if there isn't one, use the Adobe key.
119 if (_shmkey == 0) {
120 log_debug("No shared memory key specified in rcfile. Using default "
121 "for communication with other players");
122 _shmkey = 0xdd3adabd;
125 log_debug("Using shared memory key %s",
126 boost::io::group(std::hex, std::showbase, _shmkey));
128 // First get semaphore.
130 // Check if it exists already.
131 _semid = ::semget(_shmkey, 1, 0600);
133 #ifndef __amigaos4__
134 // Struct for semctl
135 union semun {
136 int val;
137 struct semi_ds* buf;
138 unsigned short* array;
140 #endif
142 semun s;
144 // If it does not exist, create it and set its value to 1.
145 if (_semid < 0) {
147 _semid = ::semget(_shmkey, 1, IPC_CREAT | 0600);
149 if (_semid < 0) {
150 log_error("Failed to get semaphore for shared memory!");
151 return false;
154 s.val = 1;
155 const int ret = ::semctl(_semid, 0, SETVAL, s);
156 if (ret < 0) {
157 log_error("Failed to set semaphore value");
158 return false;
162 // The 4th argument is neither necessary nor used, but we pass it
163 // anyway for fun.
164 const int semval = ::semctl(_semid, 0, GETVAL, s);
166 if (semval != 1) {
167 log_error("Need semaphore value of 1 for locking. Cannot "
168 "attach shared memory!");
169 return false;
172 Lock lock(*this);
174 // Then attach shared memory. See if it exists.
175 _shmid = ::shmget(_shmkey, _size, 0600);
177 // If not create it.
178 if (_shmid < 0) {
179 _shmid = ::shmget(_shmkey, _size, IPC_CREAT | 0660);
182 if (_shmid < 0) {
183 log_error("Unable to get shared memory segment!");
184 return false;
187 _addr = static_cast<iterator>(::shmat(_shmid, 0, 0));
189 if (!_addr) {
190 log_error("Unable to attach shared memory: %s",
191 std::strerror(errno));
192 return false;
195 assert(_addr);
196 return true;
199 } // end of gnash namespace
201 // Local Variables:
202 // mode: C++
203 // indent-tabs-mode: t
204 // End: