Fix a typo in xas.1 (thanks to Marcell)
[amule.git] / src / FileArea.cpp
blob8a018b99289635d34bd77abcb5efe8c2821c0846
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 1998 Vadim Zeitlin ( zeitlin@dptmaths.ens-cachan.fr )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
31 #ifdef HAVE_ERRNO_H
32 #include <errno.h>
33 #endif
35 #ifdef HAVE_SIGNAL_H
36 #include <signal.h>
37 #endif
39 #include "FileArea.h" // Interface declarations.
40 #include "FileAutoClose.h" // Needed for CFileAutoClose
42 #ifndef ENABLE_MMAP
43 # define ENABLE_MMAP 0
44 #endif
46 #define USE_MMAP (ENABLE_MMAP && defined(HAVE_MMAP) && defined(HAVE_SYSCONF) && (defined(HAVE__SC_PAGESIZE) || defined(HAVE__SC_PAGE_SIZE)))
48 #if USE_MMAP
50 #include <sys/mman.h>
52 #if defined(HAVE_SYSCONF) && defined(HAVE__SC_PAGESIZE)
53 static const long gs_pageSize = sysconf(_SC_PAGESIZE);
54 #elif defined(HAVE_SYSCONF) && defined(HAVE__SC_PAGE_SIZE)
55 static const long gs_pageSize = sysconf(_SC_PAGE_SIZE);
56 #endif
58 #endif /* USE_MMAP */
60 #if !defined(HAVE_SIGACTION) || !defined(SA_SIGINFO) || !USE_MMAP || defined(__UCLIBC__)
62 class CFileAreaSigHandler
64 public:
65 static void Init() {};
66 static void Add(CFileArea&) {};
67 static void Remove(CFileArea&) {};
68 private:
69 CFileAreaSigHandler() {};
72 #else
74 class CFileAreaSigHandler
76 public:
77 static void Init();
78 static void Add(CFileArea& area);
79 static void Remove(CFileArea& area);
80 private:
81 CFileAreaSigHandler() {};
82 static wxMutex mutex;
83 static CFileArea *first;
84 static bool initialized;
85 static struct sigaction old_segv, old_bus;
86 static void Handler(int sig, siginfo_t *info, void *ctx);
89 wxMutex CFileAreaSigHandler::mutex;
90 CFileArea * CFileAreaSigHandler::first;
91 bool CFileAreaSigHandler::initialized = false;
92 struct sigaction CFileAreaSigHandler::old_segv;
93 struct sigaction CFileAreaSigHandler::old_bus;
95 /* define MAP_ANONYMOUS for Mac OS X */
96 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
97 #define MAP_ANONYMOUS MAP_ANON
98 #endif
100 // Handle signals.
101 // The idea is to replace faulted memory with zeroes and mark
102 // the error in proper CFileArea
103 void CFileAreaSigHandler::Handler(int sig, siginfo_t *info, void *ctx)
105 CFileArea *cur;
106 // find the mapped section where violation occurred (if any)
108 wxMutexLocker lock(mutex);
109 cur = first;
110 while (cur) {
111 if (cur->m_mmap_buffer && info->si_addr >= cur->m_mmap_buffer && info->si_addr < cur->m_mmap_buffer + cur->m_length)
112 break;
113 cur = cur->m_next;
117 // mark error if found
118 if (cur && gs_pageSize > 0) {
119 cur->m_error = true;
120 char *start_addr = ((char *) info->si_addr) - (((unsigned long) info->si_addr) % gs_pageSize);
121 if (mmap(start_addr, gs_pageSize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) != MAP_FAILED)
122 return;
125 // call old handler
126 struct sigaction* sa = (sig == SIGSEGV) ? &old_segv : &old_bus;
127 if (sa->sa_flags & SA_SIGINFO)
128 sa->sa_sigaction(sig, info, ctx);
129 else if (sa->sa_handler == SIG_DFL || sa->sa_handler == SIG_IGN)
130 abort();
131 else
132 sa->sa_handler(sig);
135 void CFileAreaSigHandler::Init()
137 // init error handler if needed
138 wxMutexLocker lock(mutex);
139 if (initialized)
140 return;
142 // Set our new signal handler.
143 // Note that we safe old handlers (propably wx ones) in order
144 // to be able to call them if signal not handled as desired.
145 // These handler will be removed by wx code when wx will restore
146 // old ones
147 struct sigaction sa;
148 memset(&sa, 0, sizeof(sa));
149 sigemptyset(&sa.sa_mask);
150 sa.sa_sigaction = Handler;
151 sa.sa_flags = SA_NODEFER|SA_SIGINFO;
152 if (sigaction(SIGSEGV, &sa, &old_segv))
153 return;
154 if (sigaction(SIGBUS, &sa, &old_bus)) {
155 sigaction(SIGSEGV, &old_segv, NULL);
156 return;
158 initialized = true;
161 void CFileAreaSigHandler::Add(CFileArea& area)
163 wxMutexLocker lock(mutex);
164 area.m_next = first;
165 first = &area;
168 void CFileAreaSigHandler::Remove(CFileArea& area)
170 wxMutexLocker lock(mutex);
171 CFileArea **cur = &first;
172 while (*cur) {
173 if (*cur == &area) {
174 *cur = area.m_next;
175 area.m_next = NULL;
176 break;
178 cur = &(*cur)->m_next;
181 #endif
183 CFileArea::CFileArea()
184 : m_buffer(NULL), m_mmap_buffer(NULL), m_length(0), m_next(NULL), m_file(NULL), m_error(false)
186 CFileAreaSigHandler::Init();
190 CFileArea::~CFileArea()
192 Close();
193 CheckError();
196 bool CFileArea::Close()
198 if (m_buffer != NULL && m_mmap_buffer == NULL)
200 delete[] m_buffer;
201 m_buffer = NULL;
203 #if USE_MMAP
204 if (m_mmap_buffer)
206 munmap(m_mmap_buffer, m_length);
207 // remove from list
208 CFileAreaSigHandler::Remove(*this);
209 m_buffer = NULL;
210 m_mmap_buffer = NULL;
211 if (m_file) {
212 m_file->Unlock();
213 m_file = NULL;
216 #endif
217 return true;
221 void CFileArea::ReadAt(CFileAutoClose& file, uint64 offset, size_t count)
223 Close();
225 #if USE_MMAP
226 uint64 offEnd = offset + count;
227 if (gs_pageSize > 0 && offEnd < 0x100000000ull) {
228 uint64 offStart = offset & (~((uint64)gs_pageSize-1));
229 m_length = offEnd - offStart;
230 void *p = mmap(NULL, m_length, PROT_READ, MAP_SHARED, file.fd(), offStart);
231 if (p != MAP_FAILED) {
232 m_file = &file;
233 m_mmap_buffer = (byte*) p;
234 m_buffer = m_mmap_buffer + (offset - offStart);
236 // add to list to catch errors correctly
237 CFileAreaSigHandler::Add(*this);
238 return;
241 file.Unlock();
242 #endif
243 m_buffer = new byte[count];
244 file.ReadAt(m_buffer, offset, count);
247 #if USE_MMAP
248 void CFileArea::StartWriteAt(CFileAutoClose& file, uint64 offset, size_t count)
250 Close();
252 uint64 offEnd = offset + count;
253 if (file.GetLength() >= offEnd && gs_pageSize > 0 && offEnd < 0x100000000ull) {
254 uint64 offStart = offset & (~((uint64)gs_pageSize-1));
255 m_length = offEnd - offStart;
256 void *p = mmap(NULL, m_length, PROT_READ|PROT_WRITE, MAP_SHARED, file.fd(), offStart);
257 if (p != MAP_FAILED)
259 m_file = &file;
260 m_mmap_buffer = (byte*) p;
261 m_buffer = m_mmap_buffer + (offset - offStart);
263 // add to list to catch errors correctly
264 CFileAreaSigHandler::Add(*this);
265 return;
267 file.Unlock();
269 m_buffer = new byte[count];
271 #else
272 void CFileArea::StartWriteAt(CFileAutoClose&, uint64, size_t count)
274 Close();
275 m_buffer = new byte[count];
277 #endif
280 bool CFileArea::FlushAt(CFileAutoClose& file, uint64 offset, size_t count)
282 if (!m_buffer)
283 return false;
285 #if USE_MMAP
286 if (m_mmap_buffer) {
287 if (msync(m_mmap_buffer, m_length, MS_SYNC))
288 return false;
289 Close();
290 return true;
292 #endif
293 file.WriteAt(m_buffer, offset, count);
294 Close();
295 return true;
298 void CFileArea::CheckError()
300 bool err = m_error;
301 m_error = false;
302 if (err)
303 throw CIOFailureException(wxT("Read error, failed to read from file."));