| 204 | | |
|---|
| 205 | | # ifdef HAVE_MMAP |
|---|
| 206 | | p_sys->pagemask = sysconf (_SC_PAGE_SIZE) - 1; |
|---|
| 207 | | |
|---|
| 208 | | /* Autodetect mmap() support */ |
|---|
| 209 | | if (p_sys->b_pace_control && S_ISREG (st.st_mode) && (st.st_size > 0)) |
|---|
| 210 | | { |
|---|
| 211 | | /* TODO: Do not allow PROT_WRITE, we should not need it. |
|---|
| 212 | | * However, this far, "block" ownership seems such that whoever |
|---|
| 213 | | * "receives" a block can freely modify its content. Hence we _may_ |
|---|
| 214 | | * need PROT_WRITE not to default memory protection. |
|---|
| 215 | | * NOTE: With MAP_PRIVATE, changes are not committed to the underlying |
|---|
| 216 | | * file, write open permission is not required. |
|---|
| 217 | | */ |
|---|
| 218 | | void *addr = mmap (NULL, 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); |
|---|
| 219 | | if (addr != MAP_FAILED) |
|---|
| 220 | | { |
|---|
| 221 | | /* Does the file system support mmap? */ |
|---|
| 222 | | munmap (addr, 1); |
|---|
| 223 | | p_access->pf_read = NULL; |
|---|
| 224 | | p_access->pf_block = mmapBlock; |
|---|
| 225 | | msg_Dbg (p_this, "mmap enabled"); |
|---|
| 226 | | } |
|---|
| 227 | | else |
|---|
| 228 | | msg_Dbg (p_this, "mmap disabled (%m)"); |
|---|
| 229 | | } |
|---|
| 230 | | else |
|---|
| 231 | | msg_Dbg (p_this, "mmap disabled (non regular file)"); |
|---|
| 232 | | # endif |
|---|
| 352 | | #ifdef HAVE_MMAP |
|---|
| 353 | | # define MMAP_SIZE (1 << 20) |
|---|
| 354 | | |
|---|
| 355 | | static block_t *mmapBlock (access_t *p_access) |
|---|
| 356 | | { |
|---|
| 357 | | access_sys_t *p_sys = p_access->p_sys; |
|---|
| 358 | | |
|---|
| 359 | | const int flags = MAP_SHARED; |
|---|
| 360 | | off_t offset = p_access->info.i_pos & ~p_sys->pagemask; |
|---|
| 361 | | size_t align = p_access->info.i_pos & p_sys->pagemask; |
|---|
| 362 | | size_t length = (MMAP_SIZE > p_sys->pagemask) ? MMAP_SIZE : (p_sys->pagemask + 1); |
|---|
| 363 | | void *addr; |
|---|
| 364 | | |
|---|
| 365 | | #ifndef NDEBUG |
|---|
| 366 | | int64_t dbgpos = lseek (p_sys->fd, 0, SEEK_CUR); |
|---|
| 367 | | if (dbgpos != p_access->info.i_pos) |
|---|
| 368 | | msg_Err (p_access, "position: 0x%08llx instead of 0x%08llx", |
|---|
| 369 | | p_access->info.i_pos, dbgpos); |
|---|
| 370 | | #endif |
|---|
| 371 | | |
|---|
| 372 | | if (p_access->info.i_pos >= p_access->info.i_size) |
|---|
| 373 | | { |
|---|
| 374 | | /* End of file - check if file size changed... */ |
|---|
| 375 | | struct stat st; |
|---|
| 376 | | |
|---|
| 377 | | if ((fstat (p_sys->fd, &st) == 0) |
|---|
| 378 | | && (st.st_size != p_access->info.i_size)) |
|---|
| 379 | | { |
|---|
| 380 | | p_access->info.i_size = st.st_size; |
|---|
| 381 | | p_access->info.i_update |= INPUT_UPDATE_SIZE; |
|---|
| 382 | | } |
|---|
| 383 | | |
|---|
| 384 | | /* Really at end of file then */ |
|---|
| 385 | | if (p_access->info.i_pos >= p_access->info.i_size) |
|---|
| 386 | | { |
|---|
| 387 | | p_access->info.b_eof = VLC_TRUE; |
|---|
| 388 | | msg_Dbg (p_access, "at end of memory mapped file"); |
|---|
| 389 | | return NULL; |
|---|
| 390 | | } |
|---|
| 391 | | } |
|---|
| 392 | | |
|---|
| 393 | | if (offset + length > p_access->info.i_size) |
|---|
| 394 | | /* Don't mmap beyond end of file */ |
|---|
| 395 | | length = p_access->info.i_size - offset; |
|---|
| 396 | | |
|---|
| 397 | | assert (offset <= p_access->info.i_pos); /* and */ |
|---|
| 398 | | assert (p_access->info.i_pos < p_access->info.i_size); /* imply */ |
|---|
| 399 | | assert (offset < p_access->info.i_size); /* imply */ |
|---|
| 400 | | assert (length > 0); |
|---|
| 401 | | |
|---|
| 402 | | addr = mmap (NULL, length, PROT_READ, flags, p_sys->fd, offset); |
|---|
| 403 | | if (addr == MAP_FAILED) |
|---|
| 404 | | { |
|---|
| 405 | | msg_Err (p_access, "memory mapping failed (%m)"); |
|---|
| 406 | | intf_UserFatal (p_access, VLC_FALSE, _("File reading failed"), |
|---|
| 407 | | _("VLC could not read the file.")); |
|---|
| 408 | | msleep( INPUT_ERROR_SLEEP ); |
|---|
| 409 | | return NULL; |
|---|
| 410 | | } |
|---|
| 411 | | |
|---|
| 412 | | p_access->info.i_pos = offset + length; |
|---|
| 413 | | |
|---|
| 414 | | block_t *block = block_mmap_Alloc (addr, length); |
|---|
| 415 | | if (block == NULL) |
|---|
| 416 | | return NULL; |
|---|
| 417 | | |
|---|
| 418 | | block->p_buffer += align; |
|---|
| 419 | | block->i_buffer -= align; |
|---|
| 420 | | |
|---|
| 421 | | #ifndef NDEBUG |
|---|
| 422 | | msg_Dbg (p_access, "mapped 0x%lx bytes at %p from offset 0x%lx", |
|---|
| 423 | | (unsigned long)length, addr, (unsigned long)offset); |
|---|
| 424 | | |
|---|
| 425 | | /* Compare normal I/O with memory mapping */ |
|---|
| 426 | | char *buf = malloc (block->i_buffer); |
|---|
| 427 | | ssize_t i_read = read (p_sys->fd, buf, block->i_buffer); |
|---|
| 428 | | |
|---|
| 429 | | if (i_read != (ssize_t)block->i_buffer) |
|---|
| 430 | | msg_Err (p_access, "read %u instead of %u bytes", (unsigned)i_read, |
|---|
| 431 | | (unsigned)block->i_buffer); |
|---|
| 432 | | if (memcmp (buf, block->p_buffer, block->i_buffer)) |
|---|
| 433 | | msg_Err (p_access, "inconsistent data buffer"); |
|---|
| 434 | | free (buf); |
|---|
| 435 | | #endif |
|---|
| 436 | | |
|---|
| 437 | | return block; |
|---|
| 438 | | } |
|---|
| 439 | | #endif |
|---|