New API call burn_nominal_slowdown()
This commit is contained in:
parent
0e1f5dc3da
commit
8b9a8cfb4b
@ -1 +1 @@
|
|||||||
#define Cdrskin_timestamP "2020.08.24.132739"
|
#define Cdrskin_timestamP "2020.08.26.140343"
|
||||||
|
@ -29,6 +29,9 @@ processing tracks of more than 2 GB size.
|
|||||||
*/
|
*/
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/* For struct timeval */
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#ifndef DOXYGEN
|
#ifndef DOXYGEN
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
@ -3013,6 +3016,9 @@ void burn_drive_set_speed(struct burn_drive *d, int read, int write);
|
|||||||
MMC specifies that with the Exact bit the desired speed settings shall
|
MMC specifies that with the Exact bit the desired speed settings shall
|
||||||
either be obeyed by the drive exactly, or that the drive shall indicate
|
either be obeyed by the drive exactly, or that the drive shall indicate
|
||||||
failure and not accept the settings.
|
failure and not accept the settings.
|
||||||
|
But many drives reply no error and nevertheless adjust their read speed
|
||||||
|
only coarsly or ignore the setting after a few MB of fast read attempts.
|
||||||
|
|
||||||
The call parameters have the same meaning as with burn_drive_set_speed().
|
The call parameters have the same meaning as with burn_drive_set_speed().
|
||||||
@param d The drive to set speed for. It must be a role 1 drive.
|
@param d The drive to set speed for. It must be a role 1 drive.
|
||||||
@param read Read speed in k/s (0 is max, -1 is min).
|
@param read Read speed in k/s (0 is max, -1 is min).
|
||||||
@ -3023,6 +3029,44 @@ void burn_drive_set_speed(struct burn_drive *d, int read, int write);
|
|||||||
int burn_drive_set_speed_exact(struct burn_drive *d, int read, int write);
|
int burn_drive_set_speed_exact(struct burn_drive *d, int read, int write);
|
||||||
|
|
||||||
|
|
||||||
|
/* ts C00822 */
|
||||||
|
/** Waits until the time has elapsed since the given previous time to transmit
|
||||||
|
the given byte count with the given speed in KB/second (KB = 1000 bytes).
|
||||||
|
This call may be used between random access read operations like
|
||||||
|
burn_read_data() in order to force a slower speed than the drive is
|
||||||
|
willing to use if it gets read requests as fast as it delivers data.
|
||||||
|
|
||||||
|
The parameter us_corr carries microseconds of time deviations from one
|
||||||
|
call to the next one. Such deviations may happen because of small
|
||||||
|
inexactnesses of the sleeper function and because of temporary delays
|
||||||
|
in the data supply so that sleeping for a negative time span would have
|
||||||
|
been necessary. The next call will reduce or enlarge its own sleeping
|
||||||
|
period by this value.
|
||||||
|
|
||||||
|
@param kb_per_second the desired speed in 1000 bytes per second.
|
||||||
|
Supplied by the caller.
|
||||||
|
@max_corr the maximum backlog in microseconds which shall
|
||||||
|
be compensated by the next call. Supplied by the
|
||||||
|
caller. Not more than 1 billion = 1000 seconds.
|
||||||
|
@param prev_time time keeper updated by burn_nominal_slowdown().
|
||||||
|
The caller provides the memory and elsewise should
|
||||||
|
carry it unchanged from call to call.
|
||||||
|
@param us_corr updated by burn_nominal_slowdown(). See above.
|
||||||
|
The caller provides the memory and elsewise should
|
||||||
|
carry it unchanged from call to call.
|
||||||
|
@param b_since_prev byte count since the previous call. This number
|
||||||
|
has to be counted and supplied by the caller.
|
||||||
|
@param flag Bitfield for control purposes:
|
||||||
|
bit0= initialize *prev_time and *us_corr,
|
||||||
|
ignore other parameters, do not wait
|
||||||
|
@return 2=no wait because no usable kb_per_second , 1=success , 0=failure
|
||||||
|
@since 1.5.4
|
||||||
|
*/
|
||||||
|
int burn_nominal_slowdown(int kb_per_second, int max_corr,
|
||||||
|
struct timeval *prev_time,
|
||||||
|
int *us_corr, off_t b_since_prev, int flag);
|
||||||
|
|
||||||
|
|
||||||
/* ts A70711 */
|
/* ts A70711 */
|
||||||
/** Controls the behavior with writing when the drive buffer is suspected to
|
/** Controls the behavior with writing when the drive buffer is suspected to
|
||||||
be full. To check and wait for enough free buffer space before writing
|
be full. To check and wait for enough free buffer space before writing
|
||||||
@ -4067,10 +4111,13 @@ int burn_random_access_write(struct burn_drive *d, off_t byte_address,
|
|||||||
|
|
||||||
/* ts A81215 */
|
/* ts A81215 */
|
||||||
/** Inquire the maximum amount of readable data.
|
/** Inquire the maximum amount of readable data.
|
||||||
It is supposed that all LBAs in the range from 0 to capacity - 1
|
On DVD and BD it is supposed that all LBAs in the range from 0 to
|
||||||
can be read via burn_read_data() although some of them may never have been
|
capacity - 1 can be read via burn_read_data() although some of them may
|
||||||
recorded. If tracks are recognizable then it is better to only read
|
never have been recorded. With multi-session CD there have to be
|
||||||
LBAs which are part of some track.
|
expected unreadable TAO Run-out blocks.
|
||||||
|
If tracks are recognizable then it is better to only read LBAs which
|
||||||
|
are part of some track and on CD to be cautious about the last two blocks
|
||||||
|
of each track which might be TAO Run-out blocks.
|
||||||
If the drive is actually a large file or block device, then the capacity
|
If the drive is actually a large file or block device, then the capacity
|
||||||
is curbed to a maximum of 0x7ffffff0 blocks = 4 TB - 32 KB.
|
is curbed to a maximum of 0x7ffffff0 blocks = 4 TB - 32 KB.
|
||||||
@param d The drive from which to read
|
@param d The drive from which to read
|
||||||
|
@ -108,6 +108,7 @@ burn_msf_to_sectors;
|
|||||||
burn_msgs_obtain;
|
burn_msgs_obtain;
|
||||||
burn_msgs_set_severities;
|
burn_msgs_set_severities;
|
||||||
burn_msgs_submit;
|
burn_msgs_submit;
|
||||||
|
burn_nominal_slowdown;
|
||||||
burn_obtain_profile_name;
|
burn_obtain_profile_name;
|
||||||
burn_offst_source_new;
|
burn_offst_source_new;
|
||||||
burn_os_alloc_buffer;
|
burn_os_alloc_buffer;
|
||||||
|
@ -2765,30 +2765,57 @@ void burn_stdio_mmc_sync_cache(struct burn_drive *d)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ts A70912 */
|
/* ts C00824 : API */
|
||||||
/* Enforces eventual nominal write speed.
|
/* Enforces nominal write speed */
|
||||||
@param flag bit0= initialize *prev_time */
|
int burn_nominal_slowdown(int kb_per_second, int max_corr,
|
||||||
int burn_stdio_slowdown(struct burn_drive *d, struct timeval *prev_time,
|
struct timeval *prev_time,
|
||||||
int amount, int flag)
|
int *us_corr, off_t b_since_prev, int flag)
|
||||||
{
|
{
|
||||||
struct timeval tnow;
|
struct timeval tnow;
|
||||||
double to_wait;
|
double to_wait, goal, corr;
|
||||||
|
int abs_max_corr;
|
||||||
|
|
||||||
if (flag & 1) {
|
if (flag & 1) {
|
||||||
gettimeofday(prev_time, NULL);
|
gettimeofday(prev_time, NULL);
|
||||||
|
*us_corr = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(d->nominal_write_speed <= 0)
|
if (kb_per_second <= 0)
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
|
if (max_corr < -1.0e9 || max_corr > 1.0e9)
|
||||||
|
abs_max_corr = 1000000000;
|
||||||
|
else
|
||||||
|
abs_max_corr = abs(max_corr);
|
||||||
gettimeofday(&tnow, NULL);
|
gettimeofday(&tnow, NULL);
|
||||||
to_wait = ( ((double) amount) / (double) d->nominal_write_speed ) -
|
goal = ((double) b_since_prev) / 1000.0 / ((double) kb_per_second) +
|
||||||
(double) ( tnow.tv_sec - prev_time->tv_sec ) -
|
((double) prev_time->tv_sec) +
|
||||||
(double) ( tnow.tv_usec - prev_time->tv_usec ) / 1.0e6
|
((double) prev_time->tv_usec) / 1.0e6 +
|
||||||
- 0.001; /* best would be 1 / kernel granularity HZ */
|
((double) *us_corr) / 1.0e6 ;
|
||||||
if (to_wait >= 0.0001) {
|
to_wait = goal - ((double) tnow.tv_sec) -
|
||||||
|
((double) tnow.tv_usec) / 1.0e6;
|
||||||
|
|
||||||
|
/* usleep might be restricted to 999999 microseconds */
|
||||||
|
while (to_wait > 0.0) {
|
||||||
|
if (to_wait >= 0.5) {
|
||||||
|
usleep(500000);
|
||||||
|
to_wait -= 0.5;
|
||||||
|
} else if (to_wait >= 0.00001) {
|
||||||
usleep((int) (to_wait * 1000000.0));
|
usleep((int) (to_wait * 1000000.0));
|
||||||
|
to_wait = 0.0;
|
||||||
|
} else {
|
||||||
|
to_wait = 0.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
gettimeofday(prev_time, NULL);
|
gettimeofday(prev_time, NULL);
|
||||||
|
corr = (goal - ((double) prev_time->tv_sec) -
|
||||||
|
((double) prev_time->tv_usec) / 1.0e6) * 1.0e6;
|
||||||
|
if (corr > abs_max_corr)
|
||||||
|
*us_corr = abs_max_corr;
|
||||||
|
else if (corr < -abs_max_corr)
|
||||||
|
*us_corr = -abs_max_corr;
|
||||||
|
else
|
||||||
|
*us_corr = corr;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2801,7 +2828,7 @@ int burn_stdio_write_track(struct burn_write_opts *o, struct burn_session *s,
|
|||||||
struct burn_track *t = s->track[tnum];
|
struct burn_track *t = s->track[tnum];
|
||||||
struct burn_drive *d = o->drive;
|
struct burn_drive *d = o->drive;
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
int i, prev_sync_sector = 0;
|
int i, prev_sync_sector = 0, us_corr = 0, max_corr = 250000;
|
||||||
struct buffer *out = d->buffer;
|
struct buffer *out = d->buffer;
|
||||||
struct timeval prev_time;
|
struct timeval prev_time;
|
||||||
|
|
||||||
@ -2821,7 +2848,10 @@ int burn_stdio_write_track(struct burn_write_opts *o, struct burn_session *s,
|
|||||||
d->do_simulate = o->simulate;
|
d->do_simulate = o->simulate;
|
||||||
d->sync_cache = burn_stdio_mmc_sync_cache;
|
d->sync_cache = burn_stdio_mmc_sync_cache;
|
||||||
|
|
||||||
burn_stdio_slowdown(d, &prev_time, 0, 1); /* initialize */
|
/* initialize */
|
||||||
|
burn_nominal_slowdown(d->nominal_write_speed, max_corr,
|
||||||
|
&prev_time, &us_corr, (off_t) 0, 1);
|
||||||
|
|
||||||
for (i = 0; open_ended || i < sectors; i++) {
|
for (i = 0; open_ended || i < sectors; i++) {
|
||||||
/* transact a (CD sized) sector */
|
/* transact a (CD sized) sector */
|
||||||
if (!sector_data(o, t, 0))
|
if (!sector_data(o, t, 0))
|
||||||
@ -2834,14 +2864,25 @@ int burn_stdio_write_track(struct burn_write_opts *o, struct burn_session *s,
|
|||||||
}
|
}
|
||||||
d->progress.sector++;
|
d->progress.sector++;
|
||||||
/* Flush to disk from time to time */
|
/* Flush to disk from time to time */
|
||||||
|
if (o->stdio_fsync_size > 0) {
|
||||||
if (d->progress.sector - prev_sync_sector >=
|
if (d->progress.sector - prev_sync_sector >=
|
||||||
o->stdio_fsync_size && o->stdio_fsync_size > 0) {
|
o->stdio_fsync_size) {
|
||||||
prev_sync_sector = d->progress.sector;
|
|
||||||
if (!o->simulate)
|
if (!o->simulate)
|
||||||
burn_stdio_sync_cache(d->stdio_fd, d, 1);
|
burn_stdio_sync_cache(d->stdio_fd, d,
|
||||||
|
1);
|
||||||
|
burn_nominal_slowdown(
|
||||||
|
d->nominal_write_speed, max_corr,
|
||||||
|
&prev_time, &us_corr,
|
||||||
|
(off_t) (d->progress.sector -
|
||||||
|
prev_sync_sector) *
|
||||||
|
(off_t) 2048,
|
||||||
|
0);
|
||||||
|
prev_sync_sector = d->progress.sector;
|
||||||
|
}
|
||||||
|
} else if ((d->progress.sector % 512) == 0) {
|
||||||
|
burn_nominal_slowdown(d->nominal_write_speed, max_corr,
|
||||||
|
&prev_time, &us_corr, (off_t) (512 * 2048), 0);
|
||||||
}
|
}
|
||||||
if ((d->progress.sector % 512) == 0)
|
|
||||||
burn_stdio_slowdown(d, &prev_time, 512 * 2, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pad up buffer to next full o->obs (usually 32 kB) */
|
/* Pad up buffer to next full o->obs (usually 32 kB) */
|
||||||
|
Loading…
Reference in New Issue
Block a user