diff --git a/cdrskin/cdrfifo.c b/cdrskin/cdrfifo.c index e61c533..6d912e2 100644 --- a/cdrskin/cdrfifo.c +++ b/cdrskin/cdrfifo.c @@ -25,6 +25,10 @@ #include #include +#ifdef Cdrskin_read_o_direcT +#include +#endif /* Cdrskin_read_o_direcT */ + #include "cdrfifo.h" @@ -174,9 +178,18 @@ int Cdrfifo_new(struct CdrfifO **ff, int source_fd, int dest_fd, o->follow_up_fd_idx= -1; o->next= o->prev= NULL; o->chain_idx= 0; + +#ifdef Cdrskin_read_o_direcT + o->buffer= mmap(NULL, (size_t) buffer_size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, (off_t) 0); + if(o->buffer == MAP_FAILED) + goto failed; +#else o->buffer= TSOB_FELD(char,buffer_size); if(o->buffer==NULL) goto failed; +#endif /* Cdrskin_read_o_direcT */ + return(1); failed:; Cdrfifo_destroy(ff,0); @@ -226,8 +239,14 @@ int Cdrfifo_destroy(struct CdrfifO **ff, int flag) if(o->iso_fs_descr!=NULL) free((char *) o->iso_fs_descr); + if(o->buffer!=NULL) +#ifdef Cdrskin_read_o_direcT + munmap(o->buffer, o->buffer_size); +#else free((char *) o->buffer); +#endif /* Cdrskin_read_o_direcT */ + free((char *) o); (*ff)= NULL; return(1); @@ -659,6 +678,49 @@ return: <0 = error , 0 = idle , 1 = did some work after_write:; if(o->source_fd>=0) if(FD_ISSET((o->source_fd),rds)) { can_read= o->buffer_size - o->write_idx; + +#ifdef Cdrskin_read_o_direcT + + /* ts A91115 + This chunksize must be aligned to filesystem blocksize. + One might try to inquire the block size behind o->source_fd, but since + O_DIRECT is a dirty hack anyway, i just guess that 64 KiB is divisible + by any existing block size on Linux. + */ +#define Cdrfifo_o_direct_chunK 65536 + + if(o->write_idx < o->read_idx && o->write_idx + can_read > o->read_idx) + can_read= o->read_idx - o->write_idx; + if(o->fd_in_limit>=0.0) + if(can_read > o->fd_in_limit - o->fd_in_counter) + can_read= o->fd_in_limit - o->fd_in_counter; + /* Make sure to read with properly aligned size */ + if(can_read > Cdrfifo_o_direct_chunK) + can_read= Cdrfifo_o_direct_chunK; + else if(can_read < Cdrfifo_o_direct_chunK) + can_read= -1; + ret= 0; + if(can_read>0) + ret= read(o->source_fd,o->buffer+o->write_idx,can_read); + if(can_read < 0) { + /* waiting for a full Cdrfifo_o_direct_chunK to fit */ + if(can_write <= 0 && o->dest_fd >= 0) { + fd_set rds,wts,exs; + struct timeval wt; + + FD_ZERO(&rds); + FD_ZERO(&wts); + FD_ZERO(&exs); + FD_SET((o->dest_fd),&wts); + wt.tv_sec= 0; + wt.tv_usec= 10000; + select(o->dest_fd + 1,&rds, &wts, &exs, &wt); + + } + } else + +#else /* Cdrskin_read_o_direcT */ + if(can_read>o->chunk_size) can_read= o->chunk_size; if(o->write_idxread_idx && o->write_idx+can_read > o->read_idx) @@ -669,6 +731,9 @@ after_write:; ret= 0; if(can_read>0) ret= read(o->source_fd,o->buffer+o->write_idx,can_read); + +#endif /* ! Cdrskin_read_o_direcT */ + if(ret==-1) { /* >>> handle input error */; diff --git a/cdrskin/cdrskin.c b/cdrskin/cdrskin.c index 6825802..8f9a5a2 100644 --- a/cdrskin/cdrskin.c +++ b/cdrskin/cdrskin.c @@ -339,6 +339,23 @@ or /** Verbosity level for fifo debugging */ #define Cdrskin_verbose_debug_fifO 4 +#ifdef Cdrskin_read_o_direcT +/* Linux 2.6.18: + This can avoid low write speed via USB with 32 KB SCSI write chunks. + 64 KB write chunking is 20% more effective, though, and this size is + not in need for O_DIRECT. + Strange: Vanilla read() brings USB 32 KB WRITE down from 11x to 7.5x. + Throughput from /dev/zero to /dev/null is 230x. The disk delivers 56x. + Clearly Linux USB has a problem with 32 KB chunks. read() without O_DIRECT + makes it worse. + cdrecord and growisofs bring 11x. At least growisofs uses O_DIRECT for its + fifo input. +*/ +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +#endif /* Cdrskin_read_o_direcT */ + #include #include @@ -1388,7 +1405,11 @@ int Cdrtrack_open_source_path(struct CdrtracK *track, int *fd, int flag) if(is_wav==-3) return(0); if(is_wav==0) - *fd= open(track->source_path,O_RDONLY); +#ifdef Cdrskin_read_o_direcT + *fd= open64(track->source_path, O_RDONLY | O_DIRECT); +#else + *fd= open(track->source_path, O_RDONLY); +#endif if(*fd==-1) { fprintf(stderr,"cdrskin: failed to open source address '%s'\n", track->source_path); diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index fa59a30..b2f5af4 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2009.11.15.115923" +#define Cdrskin_timestamP "2009.11.15.152541" diff --git a/cdrskin/compile_cdrskin.sh b/cdrskin/compile_cdrskin.sh index 6093f32..b7eafcb 100755 --- a/cdrskin/compile_cdrskin.sh +++ b/cdrskin/compile_cdrskin.sh @@ -55,6 +55,9 @@ do elif test "$i" = "-no_largefile" then largefile_opts= + elif test "$i" = "-o_direct" + then + def_opts="$def_opts -DCdrskin_read_o_direcT" elif test "$i" = "-do_not_compile_cdrskin" then compile_cdrskin=0 @@ -77,6 +80,7 @@ do echo " -compile_dewav compile program test/dewav without libburn." echo " -libburn_0_7_2 set macro to match libburn-0.7.2" echo " -libburn_svn set macro to match current libburn-SVN." + echo " -o_direct use open(O_DIRECT) on fifo input (Linux only)." echo " -do_not_compile_cdrskin omit compilation of cdrskin/cdrskin." echo " -experimental use newly introduced libburn features." echo " -oldfashioned use pre-0.2.2 libburn features only."