[LTP] [PATCH 1/2] POSIX: Allow pthread_barrier_destroy() to block
Cyril Hrubis
chrubis@suse.cz
Thu Oct 12 15:34:43 CEST 2017
Hi!
> static pthread_barrier_t barrier;
> -static int thread_state;
> +static volatile int thread_state;
> #define NOT_CREATED_THREAD 1
> #define ENTERED_THREAD 2
> #define EXITING_THREAD 3
> +#define WAIT_LOOP 0xFFFFFF
>
> static void *fn_chld(void *arg)
> {
> @@ -42,73 +46,90 @@ static void *fn_chld(void *arg)
>
> pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
>
> + printf("child: barrier wait\n");
> thread_state = ENTERED_THREAD;
> + rc = pthread_barrier_wait(&barrier);
> + if (rc == PTHREAD_BARRIER_SERIAL_THREAD)
> + printf("child: got PTHREAD_BARRIER_SERIAL_THREAD\n");
> + else if (rc != 0)
> + perror("child: pthread_barrier_wait");
> + else
> + printf("child: pthread_barrier_wait returned success");
>
> - /* Child should block here */
> - printf("child: barrier wait\n");
> + thread_state = EXITING_THREAD;
> + return arg;
> +}
> +
> +static void *watchdog(void *arg)
> +{
> + int rc = 0;
> +
> + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
> +
> + sleep(1);
> + printf("watchdog: It appears pthread_barrier_destroy() is blocking\n");
> rc = pthread_barrier_wait(&barrier);
> if (rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) {
> - printf("Error: child: pthread_barrier_wait() get unexpected "
> - "return code : %d\n", rc);
> + perror("watchdog: pthread_barrier_wait");
> exit(PTS_UNRESOLVED);
> - } else if (rc == PTHREAD_BARRIER_SERIAL_THREAD) {
> - printf("child: get PTHREAD_BARRIER_SERIAL_THREAD\n");
> }
>
> - thread_state = EXITING_THREAD;
> - pthread_exit(0);
> - return NULL;
> + return arg;
> }
>
> int main(void)
> {
> int cnt = 0;
> int rc;
> - pthread_t child_thread;
> + pthread_t child_thread, watchdog_thread;
>
> printf("main: Initialize barrier with count = 2\n");
> if (pthread_barrier_init(&barrier, NULL, 2) != 0) {
> - printf("main: Error at pthread_barrier_init()\n");
> + perror("main: pthread_barrier_init");
> return PTS_UNRESOLVED;
> }
>
> printf("main: create child thread\n");
> thread_state = NOT_CREATED_THREAD;
> if (pthread_create(&child_thread, NULL, fn_chld, NULL) != 0) {
> - printf("main: Error at pthread_create()\n");
> + perror("main: pthread_create");
> + return PTS_UNRESOLVED;
> + }
> +
> + printf("main: create watchdog thread\n");
> + if (pthread_create(&watchdog_thread, NULL, watchdog, NULL) != 0) {
> + perror("main: Error at pthread_create");
> return PTS_UNRESOLVED;
> }
>
> - /* Expect the child to block */
> cnt = 0;
> - do {
> - sleep(1);
> - } while (thread_state != EXITING_THREAD && cnt++ < 2);
> + for (cnt = 0; thread_state < ENTERED_THREAD && cnt < WAIT_LOOP; cnt++)
> + sched_yield();
> + /* Yield once more to increase the probability that the child thread
> + * will call pthread_barrier_wait() before this thread reaches
> + * pthread_barrier_destroy().
> + */
> + sched_yield();
>
> if (thread_state == EXITING_THREAD) {
> - /* child thread did not block */
> - printf("Test FAILED: child thread did not block on "
> - "pthread_barrier_wait()\n");
> + printf("Test FAILED: child thread did not block on pthread_barrier_wait()\n");
> exit(PTS_FAIL);
> - } else if (thread_state != ENTERED_THREAD) {
> - printf("Unexpected thread state\n");
> + } else if (thread_state == NOT_CREATED_THREAD) {
> + printf("Child thread did not start (quick enough)\n");
> exit(PTS_UNRESOLVED);
> }
>
> printf("main: destroy barrier while child is waiting\n");
> -
> rc = pthread_barrier_destroy(&barrier);
>
> - if (rc == EBUSY) {
> - printf("main: correctly got EBUSY\n");
> - printf("Test PASSED\n");
> - } else {
> + if (rc != EBUSY) {
> printf("main: got return code: %d, %s\n", rc, strerror(rc));
> - printf
> - ("Test PASSED: Note*: Expected EBUSY, but standard says 'may' fail.\n");
> + printf("Note: POSIX recommends returning EBUSY\n");
> }
>
> - /* Cleanup (cancel thread in case it is still blocking */
> + printf("Test PASSED\n");
What about we fail the test in a case that we do not get either of
success or EBUSY? I doubt that there is any harm in making this kind of
check here with the watchdog thread in place.
Otherwise the patch looks good.
> + pthread_cancel(watchdog_thread);
> pthread_cancel(child_thread);
>
> return PTS_PASS;
> --
> 2.14.2
>
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
--
Cyril Hrubis
chrubis@suse.cz
More information about the ltp
mailing list