@@ -78,6 +78,7 @@ struct QuickList
7878end.prev = &ini;
7979end.next = NULL ;
8080}
81+ ~QuickList () {};
8182const bool Empty () const
8283{
8384return (ini.next == &end); // could also be (end.prev == &ini)
@@ -93,6 +94,7 @@ struct QuickList
9394node->prev = end.prev ;
9495node->next = &end;
9596end.prev = node;
97+ node->list = this ;
9698}
9799T* Head () const
98100{
@@ -110,11 +112,7 @@ struct QuickList
110112}
111113const bool Member (T* node) const
112114{
113- bool member (false );
114- for (T* it=ini.next ; it!=&end, member!=true ; it=Next (it))
115- if (it == node)
116- member = true ;
117- return (member);
115+ return (this == node->list );
118116}
119117static T* Prev (T* node)
120118{
@@ -130,19 +128,107 @@ struct QuickList
130128next = node->next ;
131129return (next);
132130}
133- static void Remove (T* node)
134- {
135- if (Orphan (node))
136- return ;
131+ const bool Remove (T* node)
132+ {
133+ if (! Member (node))
134+ return ( false ) ;
137135node->prev ->next = node->next ;
138136node->next ->prev = node->prev ;
139137node->prev = NULL ;
140138node->next = NULL ;
139+ node->list = NULL ;
140+ return (true );
141+ }
142+ static void RemoveNode (T* node)
143+ {
144+ if (Orphan (node))
145+ return ;
146+ node->list ->Remove (node);
147+ }
148+ static const bool Orphan (T* node)
149+ {
150+ return (NULL == node->list );
151+ }
152+ };
153+
154+ template <typename T>
155+ struct QuickListMutexed : QuickList<T>
156+ {
157+ protected:
158+ // 'mutable' required to allow operations within 'const methods'
159+ mutable QuickMutex mutex;
160+ mutable QuickEvent chomp; // signals whether there is (or not) transfers in the list
161+
162+ public:
163+ QuickListMutexed () {};
164+ QuickListMutexed (const QuickListMutexed& rhs) : QuickList<T>(rhs) {};
165+ ~QuickListMutexed () { /* this->~QuickListMutexed()*/ mutex.Enter (); mutex.Leave (); };
166+ const bool Empty () const
167+ {
168+ mutex.Enter ();
169+ const bool empty = QuickList<T>::Empty ();
170+ mutex.Leave ();
171+ return (empty);
172+ }
173+ void Append (T* node)
174+ {
175+ mutex.Enter ();
176+ const bool empty = QuickList<T>::Empty ();
177+ QuickList<T>::Append (node);
178+ if (empty)
179+ chomp.Signal ();
180+ mutex.Leave ();
181+ }
182+ T* Head () const
183+ {
184+ mutex.Enter ();
185+ T* head = QuickList<T>::Head ();
186+ mutex.Leave ();
187+ return (head);
188+ }
189+ T* Last () const
190+ {
191+ mutex.Enter ();
192+ T* last = QuickList<T>::Last ();
193+ mutex.Leave ();
194+ return (last);
195+ }
196+ const bool Member (T* node) const
197+ {
198+ mutex.Enter ();
199+ const bool member = QuickList<T>::Member (node);
200+ mutex.Leave ();
201+ return (member);
202+ }
203+ const bool Remove (T* node)
204+ {
205+ mutex.Enter ();
206+ const bool removed = QuickList<T>::Remove (node);
207+ if (QuickList<T>::Empty ())
208+ chomp.Reset ();
209+ mutex.Leave ();
210+ return (removed);
141211}
142212static const bool Orphan (T* node)
143213{
144- return ((NULL == node->prev ) && (NULL == node->next )); // (node->prev == node->next)
214+ // node->list->mutex.Enter();
215+ const bool orphan = QuickList<T>::Orphan (node);
216+ // node->list->mutex.Leave();
217+ return (orphan);
145218}
219+
220+ const bool WaitUntilTimeout (unsigned int milliseconds) const
221+ {
222+ return (chomp.WaitUntilTimeout (milliseconds));
223+ }
224+ void Wait () const
225+ {
226+ chomp.Wait ();
227+ }
228+ const bool Check () const
229+ {
230+ return (chomp.Check ());
231+ }
146232};
147233
148234} // end of 'namespace libusbemu'
@@ -155,6 +241,7 @@ struct transfer_wrapper
155241{
156242transfer_wrapper* prev;
157243transfer_wrapper* next;
244+ QuickList<transfer_wrapper>* list;
158245void * usb;
159246libusb_transfer libusb;
160247};
@@ -171,7 +258,12 @@ struct libusb_device_t
171258 struct usb_device * device;
172259 int refcount;
173260 typedef QuickList<transfer_wrapper> TListTransfers;
174- typedef std::map<int , TListTransfers> TMapIsocTransfers;
261+ struct isoc_handle
262+ {
263+ TListTransfers listTransfers;
264+ QuickThread* poReapThread;
265+ };
266+ typedef std::map<int , isoc_handle> TMapIsocTransfers;
175267 TMapIsocTransfers* isoTransfers;
176268 typedef std::map<usb_dev_handle*, libusb_device_handle> TMapHandles;
177269 TMapHandles* handles;
@@ -182,22 +274,42 @@ struct libusb_context_t
182274 typedef std::map<struct usb_device *, libusb_device> TMapDevices;
183275 TMapDevices devices;
184276 QuickMutex mutex;
185- QuickEvent processing;
277+
278+ QuickMutex mutDeliveryPool;
279+ EventList hWantToDeliverPool;
280+ EventList hAllowDeliveryPool;
281+ EventList hDoneDeliveringPool;
186282};
187283
188284
189285
286+ #define LIBUSBEMU_ERROR (msg ) libusbemu_report_error(__FILE__, __LINE__, msg)
287+ #define LIBUSBEMU_ERROR_LIBUSBWIN32 () LIBUSBEMU_ERROR(usb_strerror())
288+
190289namespace libusbemu {
191290
291+ void libusbemu_report_error (const char * file, const int line, const char * msg)
292+ {
293+ // remove source file path:
294+ int i = strlen (file);
295+ while (-1 != --i)
296+ if ((file[i] == ' /' ) || (file[i] == ' \\ ' ))
297+ break ;
298+ file = &file[++i];
299+
300+ fprintf (stderr, " ERROR in libusbemu -- source file '%s' at line %d -- %s\n " , file, line, msg);
301+ }
302+
192303transfer_wrapper* libusbemu_get_transfer_wrapper (libusb_transfer* transfer)
193304{
194305 char * raw_address ((char *)transfer);
195- char * off_address (raw_address - sizeof (void *) - 2 *sizeof (transfer_wrapper*));
306+ char * off_address (raw_address - sizeof (void *) - 2 *sizeof (transfer_wrapper*) - sizeof (QuickList<transfer_wrapper>*) );
196307 return ((transfer_wrapper*)off_address);
197308}
198309
199310libusb_device* libusbemu_register_device (libusb_context* ctx, struct usb_device * dev)
200311{
312+ RAIIMutex lock (ctx->mutex );
201313 // register the device (if not already there) ...
202314 libusb_device dummy = { ctx, dev, 0 , NULL , NULL };
203315 libusb_context::TMapDevices::iterator it = ctx->devices .insert (std::make_pair (dev,dummy)).first ;
@@ -212,6 +324,8 @@ libusb_device* libusbemu_register_device(libusb_context* ctx, struct usb_device*
212324
213325void libusbemu_unregister_device (libusb_device* dev)
214326{
327+ libusb_context* ctx (dev->ctx );
328+ RAIIMutex lock (ctx->mutex );
215329 // decrement the reference count of the device ...
216330 --(dev->refcount );
217331 // ... and unregister device if the reference count reaches zero
@@ -225,36 +339,39 @@ void libusbemu_unregister_device(libusb_device* dev)
225339 while (!allTransfers.empty ())
226340 {
227341 libusb_device::TMapIsocTransfers::iterator it (allTransfers.begin ());
228- libusb_device::TListTransfers& listTransfers (it->second );
342+ libusb_device::TListTransfers& listTransfers (it->second . listTransfers );
229343 while (!listTransfers.Empty ())
230344 {
231345 transfer_wrapper* transfer (listTransfers.Head ());
232346 // make it orphan so that it can be deleted:
233- libusb_device::TListTransfers:: Remove (transfer);
347+ listTransfers. Remove (transfer);
234348 // the following will free the wrapper object as well:
235349 libusb_free_transfer (&transfer->libusb );
236350 }
237351 allTransfers.erase (it);
238352 }
239353 SAFE_DELETE (dev->isoTransfers );
240354 }
241- libusb_context* ctx (dev->ctx );
242355 ctx->devices .erase (dev->device );
243356 }
244357}
245358
246359int libusbemu_setup_transfer (transfer_wrapper* wrapper)
247360{
248361 void *& context = wrapper->usb ;
249- if (NULL != context) // Paranoid check...
362+ // paranoid check...
363+ if (NULL != context)
250364 return (LIBUSB_ERROR_OTHER);
251365
366+ RAIIMutex lock (wrapper->libusb .dev_handle ->dev ->ctx ->mutex );
367+
252368 int ret (LIBUSB_ERROR_OTHER);
253- libusb_transfer* transfer = &wrapper->libusb ;
369+ libusb_transfer* transfer (&wrapper->libusb );
370+ usb_dev_handle* handle (transfer->dev_handle ->handle );
254371 switch (transfer->type )
255372 {
256373 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS :
257- ret = usb_isochronous_setup_async (transfer-> dev_handle -> handle , &context, transfer->endpoint , transfer->iso_packet_desc [0 ].length );
374+ ret = usb_isochronous_setup_async (handle, &context, transfer->endpoint , transfer->iso_packet_desc [0 ].length );
258375 break ;
259376 case LIBUSB_TRANSFER_TYPE_CONTROL :
260377 // libusb-0.1 does not actually support asynchronous control transfers, but this should be
@@ -276,6 +393,7 @@ int libusbemu_setup_transfer(transfer_wrapper* wrapper)
276393 {
277394 // TODO: better error handling...
278395 // what do the functions usb_***_setup_async() actually return on error?
396+ LIBUSBEMU_ERROR_LIBUSBWIN32 ();
279397 return (ret);
280398 }
281399
0 commit comments