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

Li Wang liwang@redhat.com
Thu Sep 26 07:48:44 CEST 2019


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>


More information about the ltp mailing list