Skip to content

Commit ca92bf7

Browse files
Merge pull request #1500 from ValdikSS/usb-race-condition-2.4
libusb backend: attempt to fix DRAIN_OUTPUT race condition. Fixes #1461
2 parents 7f85ba6 + 510ebb3 commit ca92bf7

1 file changed

Lines changed: 45 additions & 2 deletions

File tree

backend/usb-libusb.c

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ typedef struct usb_globals_s /* Global USB printer information */
7878
pthread_cond_t sidechannel_thread_cond;
7979
int sidechannel_thread_stop;
8080
int sidechannel_thread_done;
81+
82+
int wakeup_pipe[2]; /* Pipe for waking up select() in the main thread */
8183
} usb_globals_t;
8284

8385
/*
@@ -188,12 +190,14 @@ print_device(const char *uri, /* I - Device URI */
188190
*print_ptr; /* Pointer into print data buffer */
189191
fd_set input_set; /* Input set for select() */
190192
int nfds; /* Number of file descriptors */
193+
int nfd_max; /* Maximum file descriptor number for select() */
191194
struct timeval *timeout, /* Timeout pointer */
192195
tv; /* Time value */
193196
struct timespec cond_timeout; /* pthread condition timeout */
194197
int num_opts; /* Number of options */
195198
cups_option_t *opts; /* Options */
196199
const char *val; /* Option value */
200+
char dummy; /* select() wakeup bogus data */
197201

198202

199203
load_quirks();
@@ -205,6 +209,17 @@ print_device(const char *uri, /* I - Device URI */
205209
have_sidechannel = !fstat(CUPS_SC_FD, &sidechannel_info) &&
206210
S_ISSOCK(sidechannel_info.st_mode);
207211

212+
/*
213+
* Create a pipe for waking up the main thread from select()...
214+
*/
215+
216+
if (pipe(g.wakeup_pipe) < 0)
217+
{
218+
fprintf(stderr, "DEBUG: Unable to create wakeup pipe - %s\n",
219+
strerror(errno));
220+
return (CUPS_BACKEND_STOP);
221+
}
222+
208223
g.wait_eof = WAIT_EOF;
209224

210225
/*
@@ -346,12 +361,15 @@ print_device(const char *uri, /* I - Device URI */
346361
lseek(print_fd, 0, SEEK_SET);
347362
}
348363

364+
nfd_max = (print_fd > g.wakeup_pipe[0] ? print_fd : g.wakeup_pipe[0]) + 1;
365+
349366
while (status == CUPS_BACKEND_OK)
350367
{
351368
FD_ZERO(&input_set);
352369

353370
if (!g.print_bytes)
354371
FD_SET(print_fd, &input_set);
372+
FD_SET(g.wakeup_pipe[0], &input_set);
355373

356374
/*
357375
* Calculate select timeout...
@@ -384,7 +402,7 @@ print_device(const char *uri, /* I - Device URI */
384402
pthread_cond_signal(&g.readwrite_lock_cond);
385403
pthread_mutex_unlock(&g.readwrite_lock_mutex);
386404

387-
nfds = select(print_fd + 1, &input_set, NULL, NULL, timeout);
405+
nfds = select(nfd_max, &input_set, NULL, NULL, timeout);
388406

389407
/*
390408
* Reacquire the lock...
@@ -415,15 +433,22 @@ print_device(const char *uri, /* I - Device URI */
415433
}
416434
}
417435

436+
/*
437+
* Check if we were woken up by the sidechannel thread...
438+
*/
439+
440+
if (FD_ISSET(g.wakeup_pipe[0], &input_set))
441+
read(g.wakeup_pipe[0], &dummy, 1);
442+
418443
/*
419444
* If drain output has finished send a response...
420445
*/
421446

422447
if (g.drain_output && !nfds && !g.print_bytes)
423448
{
424449
/* Send a response... */
425-
cupsSideChannelWrite(CUPS_SC_CMD_DRAIN_OUTPUT, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
426450
g.drain_output = 0;
451+
cupsSideChannelWrite(CUPS_SC_CMD_DRAIN_OUTPUT, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
427452
}
428453

429454
/*
@@ -641,6 +666,13 @@ print_device(const char *uri, /* I - Device URI */
641666

642667
close_device(g.printer);
643668

669+
/*
670+
* Close the wakeup pipe...
671+
*/
672+
673+
close(g.wakeup_pipe[0]);
674+
close(g.wakeup_pipe[1]);
675+
644676
/*
645677
* Clean up ....
646678
*/
@@ -1885,6 +1917,17 @@ sidechannel_thread(void *reference)
18851917
stderr);
18861918

18871919
g.drain_output = 1;
1920+
pthread_mutex_lock(&g.readwrite_lock_mutex);
1921+
if (!g.readwrite_lock)
1922+
{
1923+
/*
1924+
* If main thread is inside select(), assume it has infinite
1925+
* timeout and needs to be woken up.
1926+
*/
1927+
if (write(g.wakeup_pipe[1], &data, 1) < 0)
1928+
fputs("DEBUG: Error writing to wakeup pipe\n", stderr);
1929+
}
1930+
pthread_mutex_unlock(&g.readwrite_lock_mutex);
18881931
break;
18891932

18901933
case CUPS_SC_CMD_GET_BIDI: /* Is the connection bidirectional? */

0 commit comments

Comments
 (0)