2323#include < executorch/runtime/core/result.h>
2424#include < executorch/runtime/platform/log.h>
2525
26+ // Some platforms (e.g. Xtensa) do not support pread() that we use to read the
27+ // file at different offsets simultaneously from multiple threads not affecting
28+ // each other. We list them below and use a workaround for them.
29+ #if defined(__xtensa__)
30+ #define ET_HAVE_PREAD 0
31+ #endif // defined(__xtensa__)
32+
33+ #ifndef ET_HAVE_PREAD
34+ #define ET_HAVE_PREAD 1
35+ #endif // !ET_HAVE_PREAD
36+
2637namespace torch {
2738namespace executor {
2839namespace util {
29-
3040namespace {
3141
3242/* *
@@ -226,29 +236,28 @@ ET_NODISCARD Error FileDataLoader::load_into(
226236 ET_CHECK_OR_RETURN_ERROR (
227237 buffer != nullptr , InvalidArgument, " Provided buffer cannot be null" );
228238
229- // Seek to the right place in the file.
230- off_t seek_offset = ::lseek (fd_, offset, SEEK_SET);
231- if (seek_offset != offset) {
232- ET_LOG (
233- Error,
234- " Seeking %s to offset %zu returned %zd: %s" ,
235- file_name_,
236- offset,
237- (ssize_t )seek_offset,
238- strerror (errno));
239- return Error::AccessFailed;
240- }
241-
242239 // Read the data into the aligned address.
243240 size_t needed = size;
244241 uint8_t * buf = reinterpret_cast <uint8_t *>(buffer);
242+
243+ // Make a duplicate fd if pread() is not available and we have to seek().
244+ // Cannot use the standard dup() or fcntl() calls because the returned
245+ // duplicate will share the underlying file record and affect the original fd
246+ // when seeking on multiple threads simultaneously.
247+ const auto dup_fd = ET_HAVE_PREAD ? fd_ : ::open (file_name_, O_RDONLY);
248+
245249 while (needed > 0 ) {
246- // Reads on macos will fail with EINVAL if size > INT32_MAX.
247- ssize_t nread = ::read (
248- fd_,
249- buf,
250- std::min<size_t >(
251- needed, static_cast <size_t >(std::numeric_limits<int32_t >::max ())));
250+ // Reads on macOS will fail with EINVAL if size > INT32_MAX.
251+ const auto chunk_size = std::min<size_t >(
252+ needed, static_cast <size_t >(std::numeric_limits<int32_t >::max ()));
253+ const auto nread =
254+ #if ET_HAVE_PREAD
255+ ::pread (dup_fd, buf, chunk_size, offset);
256+ #else
257+ (::lseek (dup_fd, offset, SEEK_SET) == (off_t )-1 )
258+ ? -1
259+ : ::read (dup_fd, buf, chunk_size);
260+ #endif
252261 if (nread < 0 && errno == EINTR) {
253262 // Interrupted by a signal; zero bytes read.
254263 continue ;
@@ -263,10 +272,17 @@ ET_NODISCARD Error FileDataLoader::load_into(
263272 size,
264273 offset,
265274 nread == 0 ? " EOF" : strerror (errno));
275+ if (!ET_HAVE_PREAD) {
276+ ::close (dup_fd);
277+ }
266278 return Error::AccessFailed;
267279 }
268280 needed -= nread;
269281 buf += nread;
282+ offset += nread;
283+ }
284+ if (!ET_HAVE_PREAD) {
285+ ::close (dup_fd);
270286 }
271287 return Error::Ok;
272288}
0 commit comments