[LTP] [PATCH v3] fzsync: revoke thread_b if parent hits an accidental break

Richard Palethorpe rpalethorpe@suse.de
Thu Sep 26 11:25:50 CEST 2019


Li Wang <liwang@redhat.com> writes:

> On Wed, Sep 25, 2019 at 8:13 PM Richard Palethorpe <rpalethorpe@suse.de>
> wrote:
>
>> ...
>> I'm not sure what you are saying. However you could do something like
>> this (I haven't tested it):
>>
>
> I misunderstood your words in the last mail, sorry about that.

No problem. This is also my fault.

>
>
>>
>> struct tst_fzsync_run_thread
>> {
>>         void *(*run)(void *);
>>         void *arg;
>> };
>>
>> static void tst_fzsync_thread_wrapper(void *arg)
>> {
>>         struct tst_fzsync_run_thread t = *(struct tst_fzsync_run_thread
>> *)arg;
>>
>>         pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS);
>>         pthread_setcancelstate(PTHREAD_CANCEL_ENABLE);
>>
>>         t.run(t.arg);
>> }
>>
>> static void tst_fzsync_pair_reset(..., struct tst_fzsync_run_thread *run_b)
>>
>
> I'd like to keep the tst_fzync_pair_reset() API no change to user.
>
> The patch v4.1 like below, is there any improper place in usage?

LGTM! 

>
> @@ -218,12 +219,36 @@ static void tst_fzsync_pair_init(struct
> tst_fzsync_pair *pair)
>  static void tst_fzsync_pair_cleanup(struct tst_fzsync_pair *pair)
>  {
>         if (pair->thread_b) {
> -               tst_atomic_store(1, &pair->exit);
> +               /* Revoke thread B if parent hits accidental break */
> +               if (!pair->exit) {
> +                       tst_atomic_store(1, &pair->exit);
> +                       usleep(100000);
> +                       pthread_cancel(pair->thread_b);
> +               }
>                 SAFE_PTHREAD_JOIN(pair->thread_b, NULL);
>                 pair->thread_b = 0;
>         }
>  }
>
> +/** To store the run_b pointer and pass to tst_fzsync_thread_wrapper */
> +struct tst_fzsync_run_thread {
> +       void *(*func)(void *);
> +       void *arg;
> +};
> +
> +/**
> + * Wrap run_b for tst_fzsync_pair_reset to enable pthread cancel
> + * at the start of the thread B.
> + */
> +static void *tst_fzsync_thread_wrapper(void *run_thread)
> +{
> +       struct tst_fzsync_run_thread t = *(struct tst_fzsync_run_thread
> *)run_thread;
> +
> +       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
> +       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
> +       return t.func(t.arg);
> +}
> +
>  /**
>   * Zero some stat fields
>   *
> @@ -271,8 +296,10 @@ static void tst_fzsync_pair_reset(struct
> tst_fzsync_pair *pair,
>         pair->a_cntr = 0;
>         pair->b_cntr = 0;
>         pair->exit = 0;
> -       if (run_b)
> -               SAFE_PTHREAD_CREATE(&pair->thread_b, 0, run_b, 0);
> +       if (run_b) {
> +               struct tst_fzsync_run_thread wrap_run_b = {.func = run_b,
> .arg = NULL};
> +               SAFE_PTHREAD_CREATE(&pair->thread_b, 0,
> tst_fzsync_thread_wrapper, &wrap_run_b);
> +       }
>
>         pair->exec_time_start = (float)tst_timeout_remaining();
>  }
>
>
>> Note that in any case you can't reliably cast a function pointer to a
>> void pointer without some magic. I am guessing wrapping it in a struct
>> is the clearest way to do it.
>>
>
> Good to know this, I searched on google and confirmed that the C standard
> does not allow to cast function pointer to void*, thanks!
>
>
>>
>> You can remove the arg altogether, but I kept it because we have a
>> struct anyway to wrap the function pointer.
>>
>
> Yes, to keep it make the wrapper struct is clear to understand.


-- 
Thank you,
Richard.


More information about the ltp mailing list