Linux Test Project
 help / color / mirror / Atom feed
* [LTP] [PATCH v3] fzsync: revoke thread_b if parent hits an accidental break
@ 2019-09-24 10:58 Li Wang
  2019-09-24 12:42 ` Richard Palethorpe
  0 siblings, 1 reply; 8+ messages in thread
From: Li Wang @ 2019-09-24 10:58 UTC (permalink / raw)
  To: ltp

We shouldn't rely entirely on the pair->exit flag in tst_fzsync_pair_cleanup()
since there is possible to call tst_brk() at anyplace of thread_a, that will
lead to timeout eventually because of thread_b(tst_fzsync_wait_b) fall into
an infinite(no explicit condition to exit) loop.

Thread_a path trace:
  tst_brk()
    cleanup()
      tst_fzsync_pair_cleanup()
        SAFE_PTHREAD_JOIN(pair->thread_b, NULL)
        #Or pthread_cancel(pair->thread_b)

We fix the problem via a way to kill thread_b with pthread_cancel.

Work-around: [commit 2e74d996: Check recvmmsg exists before entering fuzzy loop]
Signed-off-by: Li Wang <liwang@redhat.com>
Cc: Richard Palethorpe <rpalethorpe@suse.com>
Cc: Cyril Hrubis <chrubis@suse.cz>
---

Notes:
    Patch V2: http://lists.linux.it/pipermail/ltp/2019-January/010489.html
    Patch V1: http://lists.linux.it/pipermail/ltp/2019-January/010438.html

 include/tst_fuzzy_sync.h | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/include/tst_fuzzy_sync.h b/include/tst_fuzzy_sync.h
index f9a1947c7..152f779cb 100644
--- a/include/tst_fuzzy_sync.h
+++ b/include/tst_fuzzy_sync.h
@@ -63,6 +63,7 @@
 #include <time.h>
 #include <math.h>
 #include <stdlib.h>
+#include <pthread.h>
 #include "tst_atomic.h"
 #include "tst_timer.h"
 #include "tst_safe_pthread.h"
@@ -218,9 +219,13 @@ 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);
-		SAFE_PTHREAD_JOIN(pair->thread_b, NULL);
-		pair->thread_b = 0;
+		if (pair->exit == 1) {
+			SAFE_PTHREAD_JOIN(pair->thread_b, NULL);
+			pair->thread_b = 0;
+		} else {
+			pthread_cancel(pair->thread_b);
+			pair->thread_b = 0;
+		}
 	}
 }
 
@@ -271,8 +276,11 @@ 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)
+	if (run_b) {
+		pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
 		SAFE_PTHREAD_CREATE(&pair->thread_b, 0, run_b, 0);
+	}
 
 	pair->exec_time_start = (float)tst_timeout_remaining();
 }
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [LTP] [PATCH v3] fzsync: revoke thread_b if parent hits an accidental break
  2019-09-24 10:58 [LTP] [PATCH v3] fzsync: revoke thread_b if parent hits an accidental break Li Wang
@ 2019-09-24 12:42 ` Richard Palethorpe
  2019-09-25  8:08   ` Li Wang
  0 siblings, 1 reply; 8+ messages in thread
From: Richard Palethorpe @ 2019-09-24 12:42 UTC (permalink / raw)
  To: ltp

Hello,

Li Wang <liwang@redhat.com> writes:

> We shouldn't rely entirely on the pair->exit flag in tst_fzsync_pair_cleanup()
> since there is possible to call tst_brk() at anyplace of thread_a, that will
> lead to timeout eventually because of thread_b(tst_fzsync_wait_b) fall into
> an infinite(no explicit condition to exit) loop.
>
> Thread_a path trace:
>   tst_brk()
>     cleanup()
>       tst_fzsync_pair_cleanup()
>         SAFE_PTHREAD_JOIN(pair->thread_b, NULL)
>         #Or pthread_cancel(pair->thread_b)
>
> We fix the problem via a way to kill thread_b with pthread_cancel.

Good idea, however not an easy one to implement.

>
> Work-around: [commit 2e74d996: Check recvmmsg exists before entering fuzzy loop]
> Signed-off-by: Li Wang <liwang@redhat.com>
> Cc: Richard Palethorpe <rpalethorpe@suse.com>
> Cc: Cyril Hrubis <chrubis@suse.cz>
> ---
>
> Notes:
>     Patch V2: http://lists.linux.it/pipermail/ltp/2019-January/010489.html
>     Patch V1: http://lists.linux.it/pipermail/ltp/2019-January/010438.html
>
>  include/tst_fuzzy_sync.h | 16 ++++++++++++----
>  1 file changed, 12 insertions(+), 4 deletions(-)
>
> diff --git a/include/tst_fuzzy_sync.h b/include/tst_fuzzy_sync.h
> index f9a1947c7..152f779cb 100644
> --- a/include/tst_fuzzy_sync.h
> +++ b/include/tst_fuzzy_sync.h
> @@ -63,6 +63,7 @@
>  #include <time.h>
>  #include <math.h>
>  #include <stdlib.h>
> +#include <pthread.h>
>  #include "tst_atomic.h"
>  #include "tst_timer.h"
>  #include "tst_safe_pthread.h"
> @@ -218,9 +219,13 @@ 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);
> -		SAFE_PTHREAD_JOIN(pair->thread_b, NULL);
> -		pair->thread_b = 0;
> +		if (pair->exit == 1) {

It can just be

if (!pair->exit) {
   ...
}

We want to join the thread and set the func pointer to zero regardless
of how we exit.

> +			SAFE_PTHREAD_JOIN(pair->thread_b, NULL);
> +			pair->thread_b = 0;
> +		} else {

I suggest still setting pair->exit here and maybe sleeping for
100ms. This gives thread B chance to exit gracefully. It is possible
that if thread B is in a spin loop then the thread won't be cancelled as
asynchronous cancellation is not guaranteed by POSIX.

> +			pthread_cancel(pair->thread_b);
> +			pair->thread_b = 0;
> +		}
>  	}
>  }
>
> @@ -271,8 +276,11 @@ 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)
> +	if (run_b) {
> +		pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
> +		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

These need to go inside thread B unless I am mistaken. Which means you
must wrap the user supplied function. You can create a function which
accepts a pointer to some contiguous memory containing the user supplied function
pointer and the user supplied arg pointer.

This can then set the threads cancel type before calling the user func with
the arg.

>  		SAFE_PTHREAD_CREATE(&pair->thread_b, 0, run_b, 0);
> +	}
>
>  	pair->exec_time_start = (float)tst_timeout_remaining();
>  }

--
Thank you,
Richard.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [LTP] [PATCH v3] fzsync: revoke thread_b if parent hits an accidental break
  2019-09-24 12:42 ` Richard Palethorpe
@ 2019-09-25  8:08   ` Li Wang
  2019-09-25  8:53     ` Richard Palethorpe
  0 siblings, 1 reply; 8+ messages in thread
From: Li Wang @ 2019-09-25  8:08 UTC (permalink / raw)
  To: ltp

Hi Richard,

On Tue, Sep 24, 2019 at 8:42 PM Richard Palethorpe <rpalethorpe@suse.de>
wrote:

> ...
> It can just be
>
> if (!pair->exit) {
>    ...
> }
>
> We want to join the thread and set the func pointer to zero regardless
> of how we exit.
>

OK.


>
> > +                     SAFE_PTHREAD_JOIN(pair->thread_b, NULL);
> > +                     pair->thread_b = 0;
> > +             } else {
>
> I suggest still setting pair->exit here and maybe sleeping for
> 100ms. This gives thread B chance to exit gracefully. It is possible
> that if thread B is in a spin loop then the thread won't be cancelled as
> asynchronous cancellation is not guaranteed by POSIX.
>

Good suggestion. That'd be better to give one more time for thread B
exiting gracefully.


> > +                     pthread_cancel(pair->thread_b);
> > +                     pair->thread_b = 0;
> > +             }
> >       }
> >  }
> >
> > @@ -271,8 +276,11 @@ 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)
> > +     if (run_b) {
> > +             pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
> > +             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
>
> These need to go inside thread B unless I am mistaken. Which means you
>

Right.


> must wrap the user supplied function. You can create a function which
> accepts a pointer to some contiguous memory containing the user supplied
> function
> pointer and the user supplied arg pointer.
>

Since you have fixed the function format of thread B as void *(*run_b)(void
*) in tst_fzsync_pair_reset(), which means we have no need to take care of
the function arg pointer anymore.

So just like what I did in V2, the wrapper function could steal the real
run_b address from pthread_create(..., wrap_run_b, run_b) parameter.

-- 
Regards,
Li Wang
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.linux.it/pipermail/ltp/attachments/20190925/162118b3/attachment.htm>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [LTP] [PATCH v3] fzsync: revoke thread_b if parent hits an accidental break
  2019-09-25  8:08   ` Li Wang
@ 2019-09-25  8:53     ` Richard Palethorpe
  2019-09-25  9:43       ` Li Wang
  0 siblings, 1 reply; 8+ messages in thread
From: Richard Palethorpe @ 2019-09-25  8:53 UTC (permalink / raw)
  To: ltp

Hello,

Li Wang <liwang@redhat.com> writes:

> Hi Richard,
>
> On Tue, Sep 24, 2019 at 8:42 PM Richard Palethorpe <rpalethorpe@suse.de>
> wrote:
>
>> ...
>> It can just be
>>
>> if (!pair->exit) {
>>    ...
>> }
>>
>> We want to join the thread and set the func pointer to zero regardless
>> of how we exit.
>>
>
> OK.
>
>
>>
>> > +                     SAFE_PTHREAD_JOIN(pair->thread_b, NULL);
>> > +                     pair->thread_b = 0;
>> > +             } else {
>>
>> I suggest still setting pair->exit here and maybe sleeping for
>> 100ms. This gives thread B chance to exit gracefully. It is possible
>> that if thread B is in a spin loop then the thread won't be cancelled as
>> asynchronous cancellation is not guaranteed by POSIX.
>>
>
> Good suggestion. That'd be better to give one more time for thread B
> exiting gracefully.
>
>
>> > +                     pthread_cancel(pair->thread_b);
>> > +                     pair->thread_b = 0;
>> > +             }
>> >       }
>> >  }
>> >
>> > @@ -271,8 +276,11 @@ 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)
>> > +     if (run_b) {
>> > +             pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
>> > +             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
>>
>> These need to go inside thread B unless I am mistaken. Which means you
>>
>
> Right.
>
>
>> must wrap the user supplied function. You can create a function which
>> accepts a pointer to some contiguous memory containing the user supplied
>> function
>> pointer and the user supplied arg pointer.
>>
>
> Since you have fixed the function format of thread B as void *(*run_b)(void
> *) in tst_fzsync_pair_reset(), which means we have no need to take care of
> the function arg pointer anymore.

I think the function pointer signature would be 'void *(*run_b)(void)'
not 'void *(*run_b)(void *)'.

I doubt any test would need the arg though, because we only use one
thread and can store parameters in global variables. So you could remove
it and update the tests.

The user might need that arg if they are starting many threads, but for
now we don't have explicit support for that in the library.

>
> So just like what I did in V2, the wrapper function could steal the real
> run_b address from pthread_create(..., wrap_run_b, run_b) parameter.


--
Thank you,
Richard.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [LTP] [PATCH v3] fzsync: revoke thread_b if parent hits an accidental break
  2019-09-25  8:53     ` Richard Palethorpe
@ 2019-09-25  9:43       ` Li Wang
  2019-09-25 12:13         ` Richard Palethorpe
  0 siblings, 1 reply; 8+ messages in thread
From: Li Wang @ 2019-09-25  9:43 UTC (permalink / raw)
  To: ltp

Richard Palethorpe <rpalethorpe@suse.de> wrote:

>> must wrap the user supplied function. You can create a function which
> >> accepts a pointer to some contiguous memory containing the user supplied
> >> function
> >> pointer and the user supplied arg pointer.
> >>
> >
> > Since you have fixed the function format of thread B as void
> *(*run_b)(void
> > *) in tst_fzsync_pair_reset(), which means we have no need to take care
> of
> > the function arg pointer anymore.
>
> I think the function pointer signature would be 'void *(*run_b)(void)'
> not 'void *(*run_b)(void *)'.
>

Hmm, but at least we should respect the pthread_create()? It requires the
function prototype is ''void *(*func)(void *)'.

       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

We could unuse the arg in thread B, but declare the function prototype with
parameter "void *" is no harm.


> I doubt any test would need the arg though, because we only use one
> thread and can store parameters in global variables. So you could remove
> it and update the tests.
>
> The user might need that arg if they are starting many threads, but for
> now we don't have explicit support for that in the library.
>

Maybe we just need to note that in the lib document.


> >
> > So just like what I did in V2, the wrapper function could steal the real
> > run_b address from pthread_create(..., wrap_run_b, run_b) parameter.
>
>
> --
> Thank you,
> Richard.
>


-- 
Regards,
Li Wang
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.linux.it/pipermail/ltp/attachments/20190925/c33ecf3a/attachment-0001.htm>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [LTP] [PATCH v3] fzsync: revoke thread_b if parent hits an accidental break
  2019-09-25  9:43       ` Li Wang
@ 2019-09-25 12:13         ` Richard Palethorpe
  2019-09-26  5:48           ` Li Wang
  0 siblings, 1 reply; 8+ messages in thread
From: Richard Palethorpe @ 2019-09-25 12:13 UTC (permalink / raw)
  To: ltp

Hello,

Li Wang <liwang@redhat.com> writes:

> Richard Palethorpe <rpalethorpe@suse.de> wrote:
>
>>> must wrap the user supplied function. You can create a function which
>> >> accepts a pointer to some contiguous memory containing the user supplied
>> >> function
>> >> pointer and the user supplied arg pointer.
>> >>
>> >
>> > Since you have fixed the function format of thread B as void
>> *(*run_b)(void
>> > *) in tst_fzsync_pair_reset(), which means we have no need to take care
>> of
>> > the function arg pointer anymore.
>>
>> I think the function pointer signature would be 'void *(*run_b)(void)'
>> not 'void *(*run_b)(void *)'.
>>
>
> Hmm, but at least we should respect the pthread_create()? It requires the
> function prototype is ''void *(*func)(void *)'.
>
>        int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
>                           void *(*start_routine) (void *), void *arg);
>
> We could unuse the arg in thread B, but declare the function prototype with
> parameter "void *" is no harm.

I'm not sure what you are saying. However you could do something like
this (I haven't tested it):

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)
{
        ...

        if (run_b)
           SAFE_PTHREAD_fCREATE(..., tst_fzsync_thread_wrapper, (void *)run_b);

        ...
}

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.

You can remove the arg altogether, but I kept it because we have a
struct anyway to wrap the function pointer.

>
>
>> I doubt any test would need the arg though, because we only use one
>> thread and can store parameters in global variables. So you could remove
>> it and update the tests.
>>
>> The user might need that arg if they are starting many threads, but for
>> now we don't have explicit support for that in the library.
>>
>
> Maybe we just need to note that in the lib document.
>
>
>> >
>> > So just like what I did in V2, the wrapper function could steal the real
>> > run_b address from pthread_create(..., wrap_run_b, run_b) parameter.
>>
>>
>> --
>> Thank you,
>> Richard.
>>


--
Thank you,
Richard.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [LTP] [PATCH v3] fzsync: revoke thread_b if parent hits an accidental break
  2019-09-25 12:13         ` Richard Palethorpe
@ 2019-09-26  5:48           ` Li Wang
  2019-09-26  9:25             ` Richard Palethorpe
  0 siblings, 1 reply; 8+ messages in thread
From: Li Wang @ 2019-09-26  5:48 UTC (permalink / raw)
  To: ltp

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.


>
> 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?

@@ -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.

-- 
Regards,
Li Wang
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.linux.it/pipermail/ltp/attachments/20190926/36531b52/attachment.htm>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [LTP] [PATCH v3] fzsync: revoke thread_b if parent hits an accidental break
  2019-09-26  5:48           ` Li Wang
@ 2019-09-26  9:25             ` Richard Palethorpe
  0 siblings, 0 replies; 8+ messages in thread
From: Richard Palethorpe @ 2019-09-26  9:25 UTC (permalink / raw)
  To: ltp


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.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2019-09-26  9:25 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-09-24 10:58 [LTP] [PATCH v3] fzsync: revoke thread_b if parent hits an accidental break Li Wang
2019-09-24 12:42 ` Richard Palethorpe
2019-09-25  8:08   ` Li Wang
2019-09-25  8:53     ` Richard Palethorpe
2019-09-25  9:43       ` Li Wang
2019-09-25 12:13         ` Richard Palethorpe
2019-09-26  5:48           ` Li Wang
2019-09-26  9:25             ` Richard Palethorpe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox