New API calls burn_os_open_track_src() , burn_os_alloc_buffer()

This commit is contained in:
Thomas Schmitt 2009-11-23 18:56:18 +00:00
parent 259d1cd2b7
commit dc8ecdd77e
13 changed files with 372 additions and 68 deletions

View File

@ -115,8 +115,7 @@ test_structest_SOURCES = test/structest.c
## cdrskin construction site - ts A60816 - A91012
cdrskin_cdrskin_CPPFLAGS = -Ilibburn
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_7_3 \
$(CDRSKIN_O_DIRECT_DEF)
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_7_3
# cdrskin_cdrskin_LDADD = $(libburn_libburn_la_OBJECTS) $(LIBBURN_EXTRALIBS)
# ts A80123, change proposed by Simon Huggins to cause dynamic libburn linking

17
README
View File

@ -60,16 +60,17 @@ Warning: The trunk might contain experimental features which might not
Special ./configure options
In some situations Linux delivers a better write performance to drives if
the track input is read with O_DIRECT (see man 2 open). The input reader of
the cdrskin fifo can be told to use this peculiar read mode by :
--enable-cdrskin-fifo-odirect
In some situations Linux may deliver a better write performance to drives if
the track input is read with O_DIRECT (see man 2 open). The API call
burn_os_open_track_src() and the input readers of cdrskin and libburn fifo
can be told to use this peculiar read mode by:
--enable-track-src-odirect
But typically libburn call burn_write_opts_set_dvd_obs(opts, 64*1024) will
yield even better performance in such a situation. 64k can be made default
at configure time by :
But often libburn call burn_write_opts_set_dvd_obs(opts, 64*1024) will yield
even better performance in such a situation. 64k can be made default at
configure time by:
--enable-dvd-obs-64k
This may be combined with above --enable-cdrskin-fifo-odirect .
This may be combined with above --enable-track-src-odirect .
Make sure to re-compile all source files after running ./configure
make clean ; make

View File

@ -1 +1 @@
#define Cdrskin_timestamP "2009.11.22.115227"
#define Cdrskin_timestamP "2009.11.23.185725"

View File

@ -179,18 +179,20 @@ dnl If this would be done more specifically in Makefile.am
dnl via libburn_libburn_la_CFLAGS then undesired .o file names would emerge
CFLAGS="$CFLAGS $STATVFS_DEF"
dnl ts A91116
AC_ARG_ENABLE(cdrskin-fifo-odirect,
[ --enable-cdrskin-fifo-odirect Enable use of O_DIRECT with cdrskin fifo inlet, default=no],
, enable_cdrskin_fifo_odirect=no)
if test x$enable_cdrskin_fifo_odirect = xyes; then
CDRSKIN_O_DIRECT_DEF="-DCdrskin_read_o_direcT"
echo "enabled use of O_DIRECT with cdrskin fifo inlet"
dnl ts A91122
AC_ARG_ENABLE(track-src-odirect,
[ --enable-track-src-odirect Enable use of O_DIRECT with track input, default=no],
, enable_track_src_odirect=no)
if test x$enable_track_src_odirect = xyes; then
LIBBURN_O_DIRECT_DEF="-DLibburn_read_o_direcT"
echo "enabled use of O_DIRECT with track input"
else
CDRSKIN_O_DIRECT_DEF=
echo "disabled use of O_DIRECT with cdrskin fifo inlet"
LIBBURN_O_DIRECT_DEF=
echo "disabled use of O_DIRECT with track input"
fi
AC_SUBST(CDRSKIN_O_DIRECT_DEF)
dnl Avoid the need for libburn_libburn_la_CFLAGS in Makefile.am (ugly .o names)
dnl ### AC_SUBST(LIBBURN_O_DIRECT_DEF)
CFLAGS="$CFLAGS $LIBBURN_O_DIRECT_DEF"
dnl ts A91116
AC_ARG_ENABLE(dvd-obs-64k,

View File

@ -627,7 +627,8 @@ int burn_fifo_start(struct burn_source *source, int flag)
fs->is_started = -1;
/* create and set up ring buffer */;
fs->buf = calloc(fs->chunksize, fs->chunks);
fs->buf = burn_os_alloc_buffer(
((size_t) fs->chunksize) * (size_t) fs->chunks, 0);
if (fs->buf == NULL) {
/* >>> could not start ring buffer */;
return -1;

View File

@ -311,8 +311,10 @@ static void fifo_free(struct burn_source *source)
burn_fifo_abort(fs, 0);
if (fs->inp != NULL)
burn_source_free(fs->inp);
if (fs->buf != NULL)
free(fs->buf);
burn_os_free_buffer(fs->buf,
((size_t) fs->chunksize) * (size_t) fs->chunks, 0);
free((char *) fs);
}
@ -344,10 +346,10 @@ int burn_fifo_source_shoveller(struct burn_source *source, int flag)
free_bytes = diff - 1;
else {
free_bytes = (bufsize - wpos) + rpos - 1;
if (bufsize - wpos < fs->chunksize)
if (bufsize - wpos < fs->inp_read_size)
trans_end = 1;
}
if (free_bytes >= fs->chunksize)
if (free_bytes >= fs->inp_read_size)
break;
fifo_sleep(0);
}
@ -355,7 +357,8 @@ int burn_fifo_source_shoveller(struct burn_source *source, int flag)
/* prepare the receiving memory */
bufpt = fs->buf + wpos;
if (trans_end) {
bufpt = calloc(fs->chunksize, 1);
bufpt = burn_os_alloc_buffer(
(size_t) fs->inp_read_size, 0);
if (bufpt == NULL) {
libdax_msgs_submit(libdax_messenger, -1,
0x00000003,
@ -369,10 +372,10 @@ int burn_fifo_source_shoveller(struct burn_source *source, int flag)
/* Obtain next chunk */
if (fs->inp->read != NULL)
ret = fs->inp->read(fs->inp,
(unsigned char *) bufpt, fs->chunksize);
(unsigned char *) bufpt, fs->inp_read_size);
else
ret = fs->inp->read_xt( fs->inp,
(unsigned char *) bufpt, fs->chunksize);
(unsigned char *) bufpt, fs->inp_read_size);
if (ret > 0)
fs->in_counter += ret;
else if (ret == 0)
@ -388,15 +391,17 @@ int burn_fifo_source_shoveller(struct burn_source *source, int flag)
}
/* activate read chunk */
if (ret > fs->chunksize) /* beware of ill custom burn_source */
ret = fs->chunksize;
if (ret > fs->inp_read_size)
/* beware of ill custom burn_source */
ret = fs->inp_read_size;
if (trans_end) {
/* copy to end of buffer */
memcpy(fs->buf + wpos, bufpt, bufsize - wpos);
/* copy to start of buffer */
memcpy(fs->buf, bufpt + (bufsize - wpos),
fs->chunksize - (bufsize - wpos));
free(bufpt);
fs->inp_read_size - (bufsize - wpos));
burn_os_free_buffer(bufpt, (size_t) fs->inp_read_size,
0);
if (ret >= bufsize - wpos)
fs->buf_writepos = ret - (bufsize - wpos);
else
@ -432,7 +437,9 @@ int burn_fifo_source_shoveller(struct burn_source *source, int flag)
So in both cases the consumer is aware that reading is futile
or even fatal.
*/
free(fs->buf); /* Give up fifo buffer. Next fifo might start soon. */
if(fs->buf != NULL)
burn_os_free_buffer(fs->buf,
((size_t) fs->chunksize) * (size_t) fs->chunks, 0);
fs->buf = NULL;
fs->thread_handle= NULL;
@ -449,7 +456,9 @@ int burn_fifo_cancel(struct burn_source *source)
return(1);
}
/*
@param flag bit0= allow larger read chunks
*/
struct burn_source *burn_fifo_source_new(struct burn_source *inp,
int chunksize, int chunks, int flag)
{
@ -476,6 +485,10 @@ struct burn_source *burn_fifo_source_new(struct burn_source *inp,
fs->thread_pid = 0;
fs->thread_is_valid = 0;
fs->inp = NULL; /* set later */
if (flag & 1)
fs->inp_read_size = 32 * 1024;
else
fs->inp_read_size = chunksize;
fs->chunksize = chunksize;
fs->chunks = chunks;
fs->buf = NULL;

View File

@ -35,6 +35,7 @@ struct burn_source_fifo {
/* the burn_source for which this fifo is acting as proxy */
struct burn_source *inp;
int inp_read_size;
/* <<< up to now it was only a pipe. This is on its way out. */
int outlet[2];

View File

@ -1791,6 +1791,67 @@ void burn_source_free(struct burn_source *s);
struct burn_source *burn_file_source_new(const char *path,
const char *subpath);
/* ts A91122 : An interface to open(O_DIRECT) or similar OS tricks. */
/* <<< temporary indicator until release 0.7.4
*/
#define Libburn_has_open_trac_srC 1
/** Opens a file with eventual acceleration preparations which may depend
on the operating system and on compile time options of libburn.
You may use this call instead of open(2) for opening file descriptors
which shall be handed to burn_fd_source_new().
If you use this call then you MUST allocate the buffers which you use
with read(2) by call burn_os_alloc_buffer(). Read sizes MUST be a multiple
of a safe buffer amount. Else you risk that track data get altered during
transmission.
burn_disk_write() will allocate a suitable read/write buffer for its own
operations. A fifo created by burn_fifo_source_new() will allocate
suitable memory for its buffer if called with flag bit0 and a multiple
of a safe buffer amount.
@param path The file address to open
@param open_flags The flags as of man 2 open. Normally just O_RDONLY.
@param flag Bitfield for control purposes (unused yet, submit 0).
@return A file descriptor as of open(2). Close it by
burn_os_close_track_src().
-1 indicates failure.
@since 0.7.4
*/
int burn_os_open_track_src(char *path, int open_flags, int flag);
/** Close a file descriptor opened by burn_os_open_track_src().
@param fd Filedescriptor to be closed
@param flag Bitfield for control purposes (unused yet, submit 0).
@return like close(2): 0 on success, -1 on error
@since 0.7.4
*/
int burn_os_close_track_src(int fd, int flag);
/** Allocate a memory area that is suitable for reading with a file descriptor
opened by burn_os_open_track_src().
@param amount Number of bytes to allocate. This should be a multiple
of the operating system's i/o block size. 32 KB is
guaranteed by libburn to be safe.
@param flag Bitfield for control purposes (unused yet, submit 0).
@return The address of the allocated memory, or NULL on failure.
A non-NULL return value has finally to be disposed via
burn_os_free_buffer().
@since 0.7.4
*/
void *burn_os_alloc_buffer(size_t amount, int flag);
/** Dispose a memory area which was obtained by burn_os_alloc_buffer(),
@param buffer Memory address to be freed.
@param amount The number of bytes which was allocated at that
address.
@param flag Bitfield for control purposes (unused yet, submit 0).
@since 0.7.4
*/
int burn_os_free_buffer(void *buffer, size_t amount, int flag);
/** Creates a data source for an image file (a track) from an open
readable filedescriptor, an eventually open readable subcodes file
descriptor and eventually a fixed size in bytes.
@ -1829,7 +1890,17 @@ struct burn_source *burn_fd_source_new(int datafd, int subfd, off_t size);
a particular chunksize. E.g. libisofs demands 2048.
@param chunks The number of chunks to be allocated in ring buffer.
This value must be >= 2.
@param flag Bitfield for control purposes (unused yet, submit 0).
@param flag Bitfield for control purposes:
bit0= The read method of inp is capable of delivering
arbitrary amounts of data per call. Not only one
sector.
Suitable for inp from burn_file_source_new()
and burn_fd_source_new() if not the fd has
exotic limitations on read size.
You MUST use this on inp which uses an fd opened
with burn_os_open_track_src().
Better do not use with other inp types.
@since 0.7.4
@return A pointer to the newly created burn_source.
Later both burn_sources, inp and the returned fifo, have
to be disposed by calling burn_source_free() for each.
@ -2831,11 +2902,4 @@ int burn_drive_probe_cd_write_modes(struct burn_drive_info *drive_info)
#endif /* Libburn_pioneer_dvr_216d_dummy_probe_wM */
/* ts A91120 */
/* Allocate write buffer via mmap() rather than calloc() and use flag
SG_FLAG_DIRECT_IO when running ioctl(SG_IO).
#define Libburn_mmap_write_buffeR 1
*/
#endif /*LIBBURN_H*/

View File

@ -19,6 +19,7 @@ Present implementation: default dummy which enables libburn only to work
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#ifdef Libburn_os_has_statvfS
#include <sys/statvfs.h>
@ -227,3 +228,47 @@ int burn_os_stdio_capacity(char *path, off_t *bytes)
return 1;
}
/* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
#ifdef Libburn_read_o_direcT
/* No special O_DIRECT-like precautions are implemented here */
#endif /* Libburn_read_o_direcT */
int burn_os_open_track_src(char *path, int open_flags, int flag)
{
int fd;
fd = open(path, open_flags);
return fd;
}
int burn_os_close_track_src(int fd, int flag)
{
int ret = 0;
if(fd != -1)
ret = close(fd);
return ret;
}
void *burn_os_alloc_buffer(size_t amount, int flag)
{
void *buf = NULL;
buf = calloc(1, amount);
return buf;
}
int burn_os_free_buffer(void *buffer, size_t amount, int flag)
{
free(buffer);
return 1;
}

View File

@ -629,3 +629,47 @@ int burn_os_stdio_capacity(char *path, off_t *bytes)
return 1;
}
/* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
#ifdef Libburn_read_o_direcT
/* No special O_DIRECT-like precautions are implemented here */
#endif /* Libburn_read_o_direcT */
int burn_os_open_track_src(char *path, int open_flags, int flag)
{
int fd;
fd = open(path, open_flags);
return fd;
}
int burn_os_close_track_src(int fd, int flag)
{
int ret = 0;
if(fd != -1)
ret = close(fd);
return ret;
}
void *burn_os_alloc_buffer(size_t amount, int flag)
{
void *buf = NULL;
buf = calloc(1, amount);
return buf;
}
int burn_os_free_buffer(void *buffer, size_t amount, int flag)
{
free(buffer);
return 1;
}

View File

@ -688,3 +688,47 @@ int burn_os_stdio_capacity(char *path, off_t *bytes)
return 1;
}
/* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
#ifdef Libburn_read_o_direcT
/* No special O_DIRECT-like precautions are implemented here */
#endif /* Libburn_read_o_direcT */
int burn_os_open_track_src(char *path, int open_flags, int flag)
{
int fd;
fd = open(path, open_flags);
return fd;
}
int burn_os_close_track_src(int fd, int flag)
{
int ret = 0;
if(fd != -1)
ret = close(fd);
return ret;
}
void *burn_os_alloc_buffer(size_t amount, int flag)
{
void *buf = NULL;
buf = calloc(1, amount);
return buf;
}
int burn_os_free_buffer(void *buffer, size_t amount, int flag)
{
free(buffer);
return 1;
}

View File

@ -2,10 +2,8 @@
/* <<< ts A91112 : experiments to get better speed with USB
*/
#ifdef Libburn_mmap_write_buffeR
#define Libburn_sgio_as_growisofS 1
#endif
*/
/*
@ -56,8 +54,23 @@ sg_issue_command() sends a SCSI command to the drive, receives reply,
sg_obtain_scsi_adr() tries to obtain SCSI address parameters.
burn_os_stdio_capacity() estimates the emulated media space of stdio-drives.
burn_os_open_track_src() opens a disk file in a way that allows best
throughput with file reading and/or SCSI write command
transmission.
burn_os_close_track_src() closes a filedescriptor obtained by
burn_os_open_track_src().
burn_os_alloc_buffer() allocates a memory area that is suitable for file
descriptors issued by burn_os_open_track_src().
The buffer size may be rounded up for alignment
reasons.
burn_os_free_buffer() delete a buffer obtained by burn_os_alloc_buffer().
Porting hints are marked by the text "PORTING:".
Send feedback to libburn-hackers@pykix.org .
@ -70,6 +83,13 @@ Hint: You should also look into sg-freebsd-port.c, which is a younger and
/** PORTING : ------- OS dependent headers and definitions ------ */
#ifdef Libburn_read_o_direcT
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
#endif /* Libburn_read_o_direcT */
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
@ -176,6 +196,7 @@ static int linux_ata_enumerate_verbous = 0;
/** PORTING : ------ libburn portable headers and definitions ----- */
#include "libburn.h"
#include "transport.h"
#include "drive.h"
#include "sg.h"
@ -2065,3 +2086,90 @@ int burn_os_stdio_capacity(char *path, off_t *bytes)
return 1;
}
/* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
#ifdef Libburn_read_o_direcT
#include <sys/mman.h>
#ifdef PROT_READ
#ifdef PROT_WRITE
#ifdef MAP_SHARED
#ifdef MAP_ANONYMOUS
#ifdef MAP_FAILED
#ifdef O_DIRECT
#define Libburn_linux_do_o_direcT 1
#endif
#endif
#endif
#endif
#endif
#endif
#endif /* Libburn_read_o_direcT */
int burn_os_open_track_src(char *path, int open_flags, int flag)
{
int fd;
#ifdef Libburn_linux_do_o_direcT
fprintf(stderr,
"libburn_EXPERIMENTAL : opening track source with O_DIRECT\n");
fd = open(path, open_flags | O_DIRECT);
#else
fd = open(path, open_flags);
#endif
return fd;
}
int burn_os_close_track_src(int fd, int flag)
{
int ret = 0;
if(fd != -1)
ret = close(fd);
return ret;
}
void *burn_os_alloc_buffer(size_t amount, int flag)
{
void *buf = NULL;
#ifdef Libburn_linux_do_o_direcT
/* >>> check whether size is suitable */;
fprintf(stderr,
"libburn_EXPERIMENTAL : allocating buffer via mmap()\n");
buf = mmap(NULL, amount, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, (off_t) 0);
if (buf == MAP_FAILED)
buf = NULL;
else
memset(buf, 0, amount);
#else
buf = calloc(1, amount);
#endif /* ! Libburn_linux_do_o_direcT */
return buf;
}
int burn_os_free_buffer(void *buffer, size_t amount, int flag)
{
#ifdef Libburn_linux_do_o_direcT
munmap(buffer, amount);
#else
free(buffer);
#endif
return 1;
}

View File

@ -2313,10 +2313,6 @@ void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc)
off_t default_size;
char msg[80];
#ifdef Libburn_mmap_write_buffeR
size_t buffer_size;
#endif
/* ts A60924 : libburn/message.c gets obsoleted
burn_message_clear_queue();
@ -2332,22 +2328,11 @@ void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc)
else
d->stream_recording_start = 0;
#ifdef Libburn_mmap_write_buffeR
fprintf(stderr,
"libburn_EXPERIMENTAL: allocating write buffer via mmap()\n");
buffer_size = sizeof(struct buffer);
if (buffer_size % (64 * 1024))
buffer_size += 64 * 1024 - (buffer_size % (64 * 1024));
d->buffer = mmap(NULL, buffer_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, (off_t) 0);
if(d->buffer == MAP_FAILED)
goto fail_wo_sync;
#else
d->buffer = calloc(sizeof(struct buffer), 1);
/* ts A91122 : Get buffer suitable for sources made by
burn_os_open_track_src() */
d->buffer = burn_os_alloc_buffer(sizeof(struct buffer), 0);
if (d->buffer == NULL)
goto fail_wo_sync;
#endif /* ! Libburn_mmap_write_buffeR */
/* >>> ts A90321
@ -2569,11 +2554,8 @@ fail_wo_sync:;
ex:;
d->do_stream_recording = 0;
if (d->buffer != NULL)
#ifdef Libburn_mmap_write_buffeR
munmap(d->buffer, buffer_size);
#else
free((char *) d->buffer);
#endif
burn_os_free_buffer((char *) d->buffer,
sizeof(struct buffer), 0);
d->buffer = buffer_mem;
return;
}