diff options
Diffstat (limited to 'backend/usb-darwin.c')
-rw-r--r-- | backend/usb-darwin.c | 125 |
1 files changed, 123 insertions, 2 deletions
diff --git a/backend/usb-darwin.c b/backend/usb-darwin.c index f94059984..7bc883e5e 100644 --- a/backend/usb-darwin.c +++ b/backend/usb-darwin.c @@ -112,6 +112,12 @@ extern char **environ; #define DEBUG_WRITES 0 +/* + * WAIT_EOF_DELAY is number of seconds we'll wait for responses from + * the printer after we've finished sending all the data + */ +#define WAIT_EOF_DELAY 7 +#define WAIT_SIDE_DELAY 3 #define DEFAULT_TIMEOUT 5000L #define USB_INTERFACE_KIND CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID190) @@ -241,6 +247,11 @@ typedef struct globals_s Boolean wait_eof; int drain_output; /* Drain all pending output */ int bidi_flag; /* 0=unidirectional, 1=bidirectional */ + + pthread_mutex_t sidechannel_thread_mutex; + pthread_cond_t sidechannel_thread_cond; + int sidechannel_thread_stop; + int sidechannel_thread_done; } globals_t; @@ -333,6 +344,7 @@ print_device(const char *uri, /* I - Device URI */ UInt32 bytes; /* Bytes written */ struct timeval *timeout, /* Timeout pointer */ stimeout; /* Timeout for select() */ + struct timespec cond_timeout; /* pthread condition timeout */ /* @@ -477,6 +489,12 @@ print_device(const char *uri, /* I - Device URI */ if (have_sidechannel) { + g.sidechannel_thread_stop = 0; + g.sidechannel_thread_done = 0; + + pthread_cond_init(&g.sidechannel_thread_cond, NULL); + pthread_mutex_init(&g.sidechannel_thread_mutex, NULL); + if (pthread_create(&sidechannel_thread_id, NULL, sidechannel_thread, NULL)) { fprintf(stderr, "DEBUG: Fatal USB error.\n"); @@ -734,6 +752,101 @@ print_device(const char *uri, /* I - Device URI */ fprintf(stderr, "DEBUG: Sent %lld bytes...\n", (off_t)total_bytes); + if (!print_fd) + { + /* + * Re-enable the SIGTERM handler so pthread_kill() will work... + */ + + struct sigaction action; /* POSIX signal action */ + + memset(&action, 0, sizeof(action)); + + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_DFL; + sigaction(SIGTERM, &action, NULL); + } + + /* + * Wait for the side channel thread to exit... + */ + + if (have_sidechannel) + { + close(CUPS_SC_FD); + pthread_mutex_lock(&g.readwrite_lock_mutex); + g.readwrite_lock = 0; + pthread_cond_signal(&g.readwrite_lock_cond); + pthread_mutex_unlock(&g.readwrite_lock_mutex); + + g.sidechannel_thread_stop = 1; + pthread_mutex_lock(&g.sidechannel_thread_mutex); + if (!g.sidechannel_thread_done) + { + /* + * Wait for the side-channel thread to exit... + */ + + cond_timeout.tv_sec = time(NULL) + WAIT_SIDE_DELAY; + cond_timeout.tv_nsec = 0; + if (pthread_cond_timedwait(&g.sidechannel_thread_cond, + &g.sidechannel_thread_mutex, + &cond_timeout) != 0) + { + /* + * Force the side-channel thread to exit... + */ + + pthread_kill(sidechannel_thread_id, SIGTERM); + } + } + pthread_mutex_unlock(&g.sidechannel_thread_mutex); + + pthread_join(sidechannel_thread_id, NULL); + + pthread_cond_destroy(&g.sidechannel_thread_cond); + pthread_mutex_destroy(&g.sidechannel_thread_mutex); + } + + pthread_cond_destroy(&g.readwrite_lock_cond); + pthread_mutex_destroy(&g.readwrite_lock_mutex); + + /* + * Signal the read thread to stop... + */ + + g.read_thread_stop = 1; + + /* + * Give the read thread WAIT_EOF_DELAY seconds to complete all the data. If + * we are not signaled in that time then force the thread to exit. + */ + + pthread_mutex_lock(&g.read_thread_mutex); + + if (!g.read_thread_done) + { + cond_timeout.tv_sec = time(NULL) + WAIT_EOF_DELAY; + cond_timeout.tv_nsec = 0; + + if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex, + &cond_timeout) != 0) + { + /* + * Force the read thread to exit... + */ + + g.wait_eof = 0; + pthread_kill(read_thread_id, SIGTERM); + } + } + pthread_mutex_unlock(&g.read_thread_mutex); + + pthread_join(read_thread_id, NULL); /* wait for the read thread to return */ + + pthread_cond_destroy(&g.read_thread_cond); + pthread_mutex_destroy(&g.read_thread_mutex); + /* * Close the connection and input file and general clean up... */ @@ -942,7 +1055,12 @@ sidechannel_thread(void *reference) break; } } - while (1); + while (!g.sidechannel_thread_stop); + + pthread_mutex_lock(&g.sidechannel_thread_mutex); + g.sidechannel_thread_done = 1; + pthread_cond_signal(&g.sidechannel_thread_cond); + pthread_mutex_unlock(&g.sidechannel_thread_mutex); return NULL; } @@ -1278,7 +1396,10 @@ static kern_return_t load_classdriver(CFStringRef driverPath, { fprintf(stderr, "DEBUG: Unable to load class driver \"%s\": %s\n", bundlestr, strerror(errno)); - return (kr); + if (errno == ENOENT) + return (load_classdriver(NULL, intf, printerDriver)); + else + return (kr); } else if (bundleinfo.st_mode & S_IWOTH) { |