Upstream tarball 9552
[amule.git] / src / FileArea.cpp
blob58e330858e3ff39a839e4b4c1ce8dc2556d30cde
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 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.
20 //
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 "Logger.h" // Needed for AddDebugLogLineM
42 #ifdef HAVE_SYS_MMAN_H
43 #include <sys/mman.h>
44 #endif
46 #if !defined(HAVE_SIGACTION) || !defined(SA_SIGINFO)
48 class CFileAreaSigHandler
50 public:
51 static void Init() {};
52 static void Add(CFileArea& area) {};
53 static void Remove(CFileArea& area) {};
56 #else
58 class CFileAreaSigHandler
60 public:
61 static void Init();
62 static void Add(CFileArea& area);
63 static void Remove(CFileArea& area);
64 private:
65 static wxMutex mutex;
66 static CFileArea *first;
67 static bool initialized;
68 static struct sigaction old_segv, old_bus;
69 static void Handler(int sig, siginfo_t *info, void *ctx);
72 wxMutex CFileAreaSigHandler::mutex;
73 CFileArea * CFileAreaSigHandler::first;
74 bool CFileAreaSigHandler::initialized = false;
75 struct sigaction CFileAreaSigHandler::old_segv;
76 struct sigaction CFileAreaSigHandler::old_bus;
78 #define PAGE_SIZE 8192u
80 /* define MAP_ANONYMOUS for Mac OS X */
81 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
82 #define MAP_ANONYMOUS MAP_ANON
83 #endif
85 void CFileAreaSigHandler::Handler(int sig, siginfo_t *info, void *ctx)
87 wxMutexLocker lock(mutex);
88 CFileArea* cur = first;
89 while (cur) {
90 if (cur->m_mmap_buffer && info->si_addr >= cur->m_mmap_buffer && info->si_addr < cur->m_mmap_buffer + cur->m_length) {
91 cur->m_error = true;
92 char *start_addr = ((char *) info->si_addr) - (((unsigned long) info->si_addr) % PAGE_SIZE);
93 if (mmap(start_addr, PAGE_SIZE, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED) {
94 struct sigaction* sa = (sig == SIGSEGV) ? &old_segv : &old_bus;
95 if (sa->sa_flags & SA_SIGINFO)
96 sa->sa_sigaction(sig, info, ctx);
97 else if (sa->sa_handler == SIG_DFL || sa->sa_handler == SIG_IGN)
98 abort();
99 else
100 sa->sa_handler(sig);
102 break;
104 cur = cur->m_next;
108 void CFileAreaSigHandler::Init()
110 // init error handler if needed
111 wxMutexLocker lock(mutex);
112 if (initialized)
113 return;
115 struct sigaction sa;
116 memset(&sa, 0, sizeof(sa));
117 sigemptyset(&sa.sa_mask);
118 sa.sa_sigaction = Handler;
119 sa.sa_flags = SA_NODEFER|SA_SIGINFO;
120 if (sigaction(SIGSEGV, &sa, &old_segv))
121 return;
122 if (sigaction(SIGBUS, &sa, &old_bus)) {
123 sigaction(SIGSEGV, &old_segv, NULL);
124 return;
126 initialized = true;
129 void CFileAreaSigHandler::Add(CFileArea& area)
131 wxMutexLocker lock(mutex);
132 area.m_next = first;
133 first = &area;
136 void CFileAreaSigHandler::Remove(CFileArea& area)
138 wxMutexLocker lock(mutex);
139 CFileArea **cur = &first;
140 while (*cur) {
141 if (*cur == &area) {
142 *cur = area.m_next;
143 area.m_next = NULL;
144 break;
146 cur = &(*cur)->m_next;
149 #endif
151 CFileArea::CFileArea()
152 : m_buffer(NULL), m_mmap_buffer(NULL), m_length(0), m_next(NULL), m_error(false)
154 CFileAreaSigHandler::Init();
158 CFileArea::~CFileArea()
160 Close();
161 CheckError();
164 bool CFileArea::Close()
166 if (m_buffer != NULL && m_mmap_buffer == NULL)
168 delete[] m_buffer;
169 m_buffer = NULL;
171 #ifdef HAVE_MMAP
172 #warning using experimental MMAP file reading
173 if (m_mmap_buffer)
175 munmap(m_mmap_buffer, m_length);
176 // remove from list
177 CFileAreaSigHandler::Remove(*this);
178 m_mmap_buffer = NULL;
180 #endif
181 return true;
185 void CFileArea::Read(const CFile& file, size_t count)
187 Close();
189 #ifdef HAVE_MMAP
190 const uint64 pageSize = 8192u;
191 uint64 offset = file.GetPosition();
192 uint64 offStart = offset & (~(pageSize-1));
193 uint64 offEnd = offset + count;
194 m_length = offEnd - offStart;
195 void *p = mmap(NULL, m_length, PROT_READ, MAP_SHARED, file.fd(), offStart);
196 if (p != MAP_FAILED)
198 m_mmap_buffer = (byte*) p;
199 m_buffer = m_mmap_buffer + (offset - offStart);
200 file.Seek(offset + count);
202 // add to list to catch errors correctly
203 CFileAreaSigHandler::Add(*this);
204 return;
206 #endif
207 m_buffer = new byte[count];
208 file.Read(m_buffer, count);
211 bool CFileArea::Flush()
213 /* currently we don't support write */
214 return true;
217 void CFileArea::CheckError()
219 bool err = m_error;
220 m_error = false;
221 if (err)
222 throw CIOFailureException(wxT("Read error, failed to read from file."));