This test is being added to provoke MAXIMUM_WAIT_OBJECTS on Windows platforms.
Currently the synchronous transfer in this test hangs on Windows platforms. This is due to the following sequence of events: * There are more than MAXIMUM_WAIT_OBJECTS event objects to wait for. * WaitForMultipleObjects fails with an error. * usbi_poll detects this error and returns it. * sync_transfer_wait_for_completion() receives this error and cancels the transfer. * The transfer cancel never comes through as usbi_poll still has too many event objects. --- tests/libusbx_testlib.h | 17 +++++++++ tests/stress.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++ tests/testlib.c | 11 ++++++ 3 files changed, 124 insertions(+) diff --git a/tests/libusbx_testlib.h b/tests/libusbx_testlib.h index 8b109a2..678ff86 100644 --- a/tests/libusbx_testlib.h +++ b/tests/libusbx_testlib.h @@ -158,4 +158,21 @@ libusb_context * libusbx_testlib_init_ctx_or_fail(libusbx_testlib_ctx * tctx); libusb_device_handle * libusbx_testlib_open_test_device( libusbx_testlib_ctx * tctx, libusb_context * ctx); +/** + * Fails the test with the given reason. + */ +void libusbx_testlib_fail(libusbx_testlib_ctx * tctx, + const char * file, + int line, + const char * reason); + +/** + * Helper macro to make calling libusbx_testlib_assert() easier. + */ +#define LIBUSBX_TEST_ASSERT(tctx, statement) \ +do { \ + if (!(statement)) \ + libusbx_testlib_fail((tctx), __FILE__, __LINE__, #statement); \ +} while (0) + #endif //LIBUSBX_TESTLIB_H diff --git a/tests/stress.c b/tests/stress.c index f64f4b7..c0868f6 100644 --- a/tests/stress.c +++ b/tests/stress.c @@ -144,12 +144,108 @@ static libusbx_testlib_result test_default_context_change(libusbx_testlib_ctx * return TEST_STATUS_SUCCESS; } +void LIBUSB_CALL transfer_cb(struct libusb_transfer * transfer) +{ + int * done = (int*) transfer->user_data; + *done = 1; +} + +#define GET_MANY_CFG_COUNT 64 +/** Tests many concurrent getting device configuration control requests. */ +static libusbx_testlib_result test_many_get_configuration_requests( + libusbx_testlib_ctx * tctx) +{ + struct libusb_transfer* transfers[GET_MANY_CFG_COUNT]; + unsigned char transfer_data[GET_MANY_CFG_COUNT][LIBUSB_CONTROL_SETUP_SIZE]; + int transfer_done[GET_MANY_CFG_COUNT]; + unsigned char data[1]; + int i, r, all_done; + libusb_context * ctx = NULL; + libusb_device_handle * dev = NULL; + + libusbx_testlib_skip_if_no_device(tctx); + ctx = libusbx_testlib_init_ctx_or_fail(tctx); + dev = libusbx_testlib_open_test_device(tctx, ctx); + + memset(transfers, 0, sizeof(transfers)); + memset(transfer_data, 0, sizeof(transfer_data)); + memset(transfer_done, 0, sizeof(transfer_done)); + + /* Issue all the control transfers */ + for(i = 0; i < GET_MANY_CFG_COUNT; ++i) { + transfers[i] = libusb_alloc_transfer(0); + LIBUSBX_TEST_ASSERT(tctx, transfers[i] != NULL); + + libusb_fill_control_setup(transfer_data[i], + LIBUSB_ENDPOINT_IN | + LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_DEVICE, + LIBUSB_REQUEST_GET_CONFIGURATION, + 0, 0, 1); + libusb_fill_control_transfer(transfers[i], + dev, transfer_data[i], + &transfer_cb, &transfer_done[i], + 60000); + + r = libusb_submit_transfer(transfers[i]); + LIBUSBX_TEST_ASSERT(tctx, r == LIBUSB_SUCCESS || r == LIBUSB_ERROR_NOT_SUPPORTED); + if (r == LIBUSB_ERROR_NOT_SUPPORTED) { + /* All platforms should support at least 16 concurrent transfers */ + LIBUSBX_TEST_ASSERT(tctx, i > 16); + /* Mark this request as already done */ + transfer_done[i] = 1; + } + } + + /* Issue a synchronous control transfer, this tests the error handling + * in the synchronous case. */ + r = libusb_control_transfer(dev, + LIBUSB_ENDPOINT_IN | + LIBUSB_REQUEST_TYPE_STANDARD | + LIBUSB_RECIPIENT_DEVICE, + LIBUSB_REQUEST_GET_CONFIGURATION, + 0, + 0, + data, sizeof(data), 1000); + LIBUSBX_TEST_ASSERT(tctx, r == 1 || + r == LIBUSB_SUCCESS || r == LIBUSB_ERROR_NOT_SUPPORTED); + + /* Process events until all the transfers are finished. + * This isn't done in a very sensible way as it just polls + * every 250ms to see if all the transfers have completed. */ + do { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 250000; + r = libusb_handle_events_timeout(ctx, &tv); + LIBUSBX_TEST_ASSERT(tctx, r == LIBUSB_SUCCESS); + /* Check if all the transfers are done */ + all_done = 1; + for (i = 0; i < GET_MANY_CFG_COUNT; ++i) { + if (!transfer_done[i]) + all_done = 0; + } + } while (!all_done); + + /* Destroy all the transfers */ + for(i = 0; i < GET_MANY_CFG_COUNT; ++i) { + libusb_free_transfer(transfers[i]); + transfers[i] = NULL; + } + + libusb_close(dev); + libusb_exit(ctx); + return TEST_STATUS_SUCCESS; + +} + /* Fill in the list of tests. */ static const libusbx_testlib_test tests[] = { LIBUSBX_NAMED_TEST(init_and_exit), LIBUSBX_NAMED_TEST(get_device_list), LIBUSBX_NAMED_TEST(many_device_lists), LIBUSBX_NAMED_TEST(default_context_change), + LIBUSBX_NAMED_TEST(many_get_configuration_requests), LIBUSBX_NULL_TEST }; diff --git a/tests/testlib.c b/tests/testlib.c index 3437591..c804a3b 100644 --- a/tests/testlib.c +++ b/tests/testlib.c @@ -373,3 +373,14 @@ libusb_device_handle * libusbx_testlib_open_test_device( } return dev; } + +void libusbx_testlib_fail( + libusbx_testlib_ctx * tctx, + const char * file, + int line, + const char * reason) +{ + libusbx_testlib_logf(tctx, "Assert failure, %s:%d %s", + file, line, reason); + libusbx_testlib_finish_current_test(tctx, TEST_STATUS_FAILURE); +} -- 1.7.9.5 ------------------------------------------------------------------------------ This SF.net email is sponsored by Windows: Build for Windows Store. http://p.sf.net/sfu/windows-dev2dev _______________________________________________ libusbx-devel mailing list libusbx-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libusbx-devel