From dc8ecdd77e0bf0f072ca711b845c099608fc85e4 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Mon, 23 Nov 2009 18:56:18 +0000 Subject: [PATCH] New API calls burn_os_open_track_src() , burn_os_alloc_buffer() --- Makefile.am | 3 +- README | 17 +++--- cdrskin/cdrskin_timestamp.h | 2 +- configure.ac | 22 +++---- libburn/async.c | 3 +- libburn/file.c | 37 ++++++++---- libburn/file.h | 1 + libburn/libburn.h | 80 ++++++++++++++++++++++--- libburn/sg-dummy.c | 45 ++++++++++++++ libburn/sg-freebsd-port.c | 44 ++++++++++++++ libburn/sg-freebsd.c | 44 ++++++++++++++ libburn/sg-linux.c | 114 +++++++++++++++++++++++++++++++++++- libburn/write.c | 28 ++------- 13 files changed, 372 insertions(+), 68 deletions(-) diff --git a/Makefile.am b/Makefile.am index 6ee8d43..260e3e4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/README b/README index 0698ac8..ef944a6 100644 --- a/README +++ b/README @@ -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 diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index d35037f..1ae1055 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2009.11.22.115227" +#define Cdrskin_timestamP "2009.11.23.185725" diff --git a/configure.ac b/configure.ac index 7cbb927..6c2f6c4 100644 --- a/configure.ac +++ b/configure.ac @@ -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, diff --git a/libburn/async.c b/libburn/async.c index 64b9a67..4611e28 100644 --- a/libburn/async.c +++ b/libburn/async.c @@ -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; diff --git a/libburn/file.c b/libburn/file.c index 236f46a..c5e4a71 100644 --- a/libburn/file.c +++ b/libburn/file.c @@ -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; diff --git a/libburn/file.h b/libburn/file.h index 1cee375..c8df2af 100644 --- a/libburn/file.h +++ b/libburn/file.h @@ -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]; diff --git a/libburn/libburn.h b/libburn/libburn.h index 16d9b19..a4665d1 100644 --- a/libburn/libburn.h +++ b/libburn/libburn.h @@ -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*/ diff --git a/libburn/sg-dummy.c b/libburn/sg-dummy.c index 0613c50..d1bd2f6 100644 --- a/libburn/sg-dummy.c +++ b/libburn/sg-dummy.c @@ -19,6 +19,7 @@ Present implementation: default dummy which enables libburn only to work #include #include #include +#include #ifdef Libburn_os_has_statvfS #include @@ -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; +} + diff --git a/libburn/sg-freebsd-port.c b/libburn/sg-freebsd-port.c index ca31ac0..3ab1b48 100644 --- a/libburn/sg-freebsd-port.c +++ b/libburn/sg-freebsd-port.c @@ -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; +} + diff --git a/libburn/sg-freebsd.c b/libburn/sg-freebsd.c index 83a5920..d74dab9 100644 --- a/libburn/sg-freebsd.c +++ b/libburn/sg-freebsd.c @@ -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; +} + diff --git a/libburn/sg-linux.c b/libburn/sg-linux.c index 5609f8f..67bef29 100644 --- a/libburn/sg-linux.c +++ b/libburn/sg-linux.c @@ -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 #include #include @@ -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 + +#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; +} + diff --git a/libburn/write.c b/libburn/write.c index c65d280..8daea2f 100644 --- a/libburn/write.c +++ b/libburn/write.c @@ -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; }