@@ -31,6 +31,30 @@ namespace {
3131// locale-independent conversions
3232const std::locale clocale = std::locale(" C" );
3333
34+ // not all SANE backends are able to handle concurrency,
35+ // so we use our own list of busy devices here.
36+ std::vector<std::pair<std::string, SANE_Handle>> s_busy_devices;
37+ std::mutex s_busy_devices_mutex;
38+
39+ bool is_busy_device (const std::string& name)
40+ {
41+ for (const auto & entry : s_busy_devices) {
42+ if (entry.first == name)
43+ return true ;
44+ }
45+ return false ;
46+ }
47+
48+ void clear_busy_device (SANE_Handle h)
49+ {
50+ for (auto it = s_busy_devices.begin (); it != s_busy_devices.end (); ++it) {
51+ if (it->second == h) {
52+ s_busy_devices.erase (it);
53+ break ;
54+ }
55+ }
56+ }
57+
3458} // namespace
3559
3660namespace sanecpp {
@@ -484,6 +508,11 @@ option::unit() const
484508device_handle
485509open (const std::string& name, SANE_Status* pStatus)
486510{
511+ std::unique_lock<std::mutex> lock (s_busy_devices_mutex);
512+ if (is_busy_device (name)) {
513+ *pStatus = SANE_STATUS_DEVICE_BUSY;
514+ return std::shared_ptr<void >();
515+ }
487516 sane_init_addref ();
488517 log << " sane_open(" << name << " ) -> " ;
489518 SANE_Handle h;
@@ -496,7 +525,9 @@ open(const std::string& name, SANE_Status* pStatus)
496525 {
497526 void operator ()(SANE_Handle h) const
498527 {
528+ std::unique_lock<std::mutex> lock (s_busy_devices_mutex);
499529 log << " sane_close(" << h << " )" << std::endl;
530+ clear_busy_device (h);
500531 ::sane_close (h);
501532 sane_init_release ();
502533 }
@@ -539,16 +570,9 @@ enumerate_devices(bool localonly)
539570}
540571
541572session::session (const std::string& devicename)
542- : m_status(SANE_STATUS_GOOD)
543- {
544- m_device = sanecpp::open (devicename, &m_status);
545- init ();
546- }
547-
548- session::session (device_handle h)
549- : m_device(h)
550- , m_status(h ? SANE_STATUS_GOOD : SANE_STATUS_DEVICE_BUSY)
573+ : m_sane_status(SANE_STATUS_GOOD)
551574{
575+ m_device = sanecpp::open (devicename, &m_sane_status);
552576 init ();
553577}
554578
@@ -564,15 +588,29 @@ session::~session()
564588session&
565589session::start ()
566590{
567- m_status = ::sane_start (m_device.get ());
568- switch (m_status) {
591+ if (m_session_state != pristine) {
592+ log << " session::start(): trying to re-initialize session" ;
593+ return *this ;
594+ }
595+ if (m_sane_status != SANE_STATUS_GOOD) {
596+ log << " session::start(): " << m_sane_status << " at entry" << std::endl;
597+ return *this ;
598+ }
599+
600+ m_sane_status = ::sane_start (m_device.get ());
601+ switch (m_sane_status) {
569602 case SANE_STATUS_GOOD:
570603 break ;
571604 default :
572- log << " sane_start(" << m_device.get () << " ): " << m_status << std::endl;
605+ log << " sane_start(" << m_device.get () << " ): " << m_sane_status << std::endl;
606+ }
607+ if (m_sane_status == SANE_STATUS_GOOD)
608+ m_sane_status = ::sane_get_parameters (m_device.get (), &m_parameters);
609+
610+ if (m_sane_status == SANE_STATUS_GOOD) {
611+ m_session_state = initialized;
612+ m_session_state_changed.notify_all ();
573613 }
574- if (m_status == SANE_STATUS_GOOD)
575- m_status = ::sane_get_parameters (m_device.get (), &m_parameters);
576614 return *this ;
577615}
578616
@@ -582,13 +620,24 @@ session::cancel()
582620 if (m_device) {
583621 log << " sane_cancel(" << m_device.get () << " )" << std::endl;
584622 ::sane_cancel (m_device.get());
623+ std::unique_lock<std::mutex> lock (m_session_state_mutex);
624+ while (m_session_state == reading) {
625+ m_session_state_changed.wait (lock);
626+ }
585627 }
586628 return *this ;
587629}
588630
589631session&
590632session::read (std::vector<char >& buffer)
591633{
634+ if (m_session_state != initialized) {
635+ log << " session::read(): trying to read from uninitialized session" ;
636+ return *this ;
637+ }
638+ m_session_state = reading;
639+ m_session_state_changed.notify_all ();
640+
592641 SANE_Status status = SANE_STATUS_GOOD;
593642 size_t total = 0 ;
594643 SANE_Byte* p = reinterpret_cast <SANE_Byte*>(buffer.data ());
@@ -604,7 +653,10 @@ session::read(std::vector<char>& buffer)
604653 default :
605654 log << " sane_read(" << m_device.get () << " ): " << status << std::endl;
606655 }
607- m_status = status;
656+ m_sane_status = status;
657+
658+ m_session_state = initialized;
659+ m_session_state_changed.notify_all ();
608660 return *this ;
609661}
610662
0 commit comments