2 // This file is part of the aMule Project.
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 )
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
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
39 #include "FileArea.h" // Interface declarations.
40 #include "FileAutoClose.h" // Needed for CFileAutoClose
43 # define ENABLE_MMAP 0
46 #define USE_MMAP (ENABLE_MMAP && defined(HAVE_MMAP) && defined(HAVE_SYSCONF) && (defined(HAVE__SC_PAGESIZE) || defined(HAVE__SC_PAGE_SIZE)))
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
);
60 #if !defined(HAVE_SIGACTION) || !defined(SA_SIGINFO) || !USE_MMAP || defined(__UCLIBC__)
62 class CFileAreaSigHandler
65 static void Init() {};
66 static void Add(CFileArea
&) {};
67 static void Remove(CFileArea
&) {};
69 CFileAreaSigHandler() {};
74 class CFileAreaSigHandler
78 static void Add(CFileArea
& area
);
79 static void Remove(CFileArea
& area
);
81 CFileAreaSigHandler() {};
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
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
)
106 // find the mapped section where violation occurred (if any)
108 wxMutexLocker
lock(mutex
);
111 if (cur
->m_mmap_buffer
&& info
->si_addr
>= cur
->m_mmap_buffer
&& info
->si_addr
< cur
->m_mmap_buffer
+ cur
->m_length
)
117 // mark error if found
118 if (cur
&& gs_pageSize
> 0) {
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
)
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
)
135 void CFileAreaSigHandler::Init()
137 // init error handler if needed
138 wxMutexLocker
lock(mutex
);
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
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
))
154 if (sigaction(SIGBUS
, &sa
, &old_bus
)) {
155 sigaction(SIGSEGV
, &old_segv
, NULL
);
161 void CFileAreaSigHandler::Add(CFileArea
& area
)
163 wxMutexLocker
lock(mutex
);
168 void CFileAreaSigHandler::Remove(CFileArea
& area
)
170 wxMutexLocker
lock(mutex
);
171 CFileArea
**cur
= &first
;
178 cur
= &(*cur
)->m_next
;
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()
196 bool CFileArea::Close()
198 if (m_buffer
!= NULL
&& m_mmap_buffer
== NULL
)
206 munmap(m_mmap_buffer
, m_length
);
208 CFileAreaSigHandler::Remove(*this);
210 m_mmap_buffer
= NULL
;
221 void CFileArea::ReadAt(CFileAutoClose
& file
, uint64 offset
, size_t count
)
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
) {
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);
243 m_buffer
= new byte
[count
];
244 file
.ReadAt(m_buffer
, offset
, count
);
248 void CFileArea::StartWriteAt(CFileAutoClose
& file
, uint64 offset
, size_t count
)
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
);
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);
269 m_buffer
= new byte
[count
];
272 void CFileArea::StartWriteAt(CFileAutoClose
&, uint64
, size_t count
)
275 m_buffer
= new byte
[count
];
280 bool CFileArea::FlushAt(CFileAutoClose
& file
, uint64 offset
, size_t count
)
287 if (msync(m_mmap_buffer
, m_length
, MS_SYNC
))
293 file
.WriteAt(m_buffer
, offset
, count
);
298 void CFileArea::CheckError()
303 throw CIOFailureException(wxT("Read error, failed to read from file."));