Skip to content

Commit 5145d3f

Browse files
committed
added helper function 'libusbemu_clear_transfer()' to facilitate 'libusbemu.cpp' tasks
added QuickListMutexed<T>: not being used right now, may prove itself useful in the future... added libusbemu/libusb-win32 error reporting routines and macros Signed-off-by: Marcos Paulo Berteli Slomp <mslomp@gmail.com>
1 parent 16d43bb commit 5145d3f

File tree

1 file changed

+137
-19
lines changed

1 file changed

+137
-19
lines changed

platform/windows/libusb10emu/libusb-1.0/libusbemu_internal.h

Lines changed: 137 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ struct QuickList
7878
end.prev = &ini;
7979
end.next = NULL;
8080
}
81+
~QuickList() {};
8182
const bool Empty() const
8283
{
8384
return(ini.next == &end); // could also be (end.prev == &ini)
@@ -93,6 +94,7 @@ struct QuickList
9394
node->prev = end.prev;
9495
node->next = &end;
9596
end.prev = node;
97+
node->list = this;
9698
}
9799
T* Head() const
98100
{
@@ -110,11 +112,7 @@ struct QuickList
110112
}
111113
const 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
}
119117
static T* Prev(T* node)
120118
{
@@ -130,19 +128,107 @@ struct QuickList
130128
next = node->next;
131129
return(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);
137135
node->prev->next = node->next;
138136
node->next->prev = node->prev;
139137
node->prev = NULL;
140138
node->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
}
142212
static 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
{
156242
transfer_wrapper* prev;
157243
transfer_wrapper* next;
244+
QuickList<transfer_wrapper>* list;
158245
void* usb;
159246
libusb_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+
190289
namespace 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+
192303
transfer_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

199310
libusb_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

213325
void 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

246359
int 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

Comments
 (0)