[LTP] [PATCH v2 03/13] hugeshmctl01: Convert to LTP synchronisation primitives

Punit Agrawal punit.agrawal@arm.com
Mon Nov 27 18:34:37 CET 2017


Cyril Hrubis <chrubis@suse.cz> writes:

> Hi!
>>  static void stat_setup(void);
>>  static void stat_cleanup(void);
>>  static void set_setup(void);
>> @@ -141,19 +139,10 @@ void *set_shmat(void)
>>   */
>>  static void stat_setup(void)
>>  {
>> -	int i, rval;
>> +	int i;
>>  	void *test;
>>  	pid_t pid;
>> -	sigset_t newmask, oldmask;
>> -	struct sigaction sa;
>> -
>> -	memset (&sa, '\0', sizeof(sa));
>> -	sa.sa_handler = sighandler;
>> -	sa.sa_flags = 0;
>> -	TEST(sigaction(SIGUSR1, &sa, NULL));
>> -	if (TEST_RETURN == -1)
>> -		tst_brk(TBROK | TRERRNO,
>> -				"SIGSEGV signal setup failed");
>> +
>>  	/*
>>  	 * The first time through, let the children attach the memory.
>>  	 * The second time through, attach the memory first and let
>> @@ -168,21 +157,6 @@ static void stat_setup(void)
>>  		set_shared = set_shmat();
>>  	}
>>  
>> -	/*
>> -	 * Block SIGUSR1 before children pause for a signal
>> -	 * Doing so to avoid the risk that the parent cleans up
>> -	 * children by calling stat_cleanup() before children call
>> -	 * call pause() so that children sleep forever(this is a
>> -	 * side effect of the arbitrary usleep time below).
>> -	 * In FIRST, children call shmat. If children sleep forever,
>> -	 * those attached shm can't be released so some other shm
>> -	 * tests will fail a lot.
>> -	 */
>> -	sigemptyset(&newmask);
>> -	sigaddset(&newmask, SIGUSR1);
>> -	if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
>> -		tst_brk(TBROK | TERRNO, "block SIGUSR1 error");
>> -
>>  	for (i = 0; i < N_ATTACH; i++) {
>>  		switch (pid = SAFE_FORK()) {
>>  		case 0:
>> @@ -191,39 +165,24 @@ static void stat_setup(void)
>>  			/* do an assignement for fun */
>>  			*(int *)test = i;
>>  
>> -			/*
>> -			 * sigsuspend until we get a signal from stat_cleanup()
>> -			 * use sigsuspend instead of pause to avoid children
>> -			 * infinite sleep without getting SIGUSR1 from parent
>> -			 */
>> -			rval = sigsuspend(&oldmask);
>> -			if (rval != -1)
>> -				tst_brk(TBROK | TERRNO, "sigsuspend");
>> -
>> -			/*
>> -			 * don't have to block SIGUSR1 any more,
>> -			 * recover the mask
>> -			 */
>> -			if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
>> -				tst_brk(TBROK | TERRNO,
>> -					 "child sigprocmask");
>> +			/* If last child then wake the parent */
>> +			if (i == N_ATTACH - 1)
>> +				TST_CHECKPOINT_WAKE(0);
>
> As far as I can tell the assumption that the children are executed in
> any order does not hold at all. So the parent should wait for _each_ of
> them separately.

Good catch. I see the problem with the patch in the scenario where the
N-1 th child executes TST_CHECKPOINT_WAKE(0) before the other children
have progressed past the write to "test".

I'll fix it as per your suggestion below.

>
> I guess that we have to suspend the parent process with
> TST_CHECKPOINT_WAIT() after each fork() and wait till the children wakes
> up the parent before we attempt to fork next child.
>

>> +			TST_CHECKPOINT_WAIT(1);
>>  
>>  			/* now we're back - detach the memory and exit */
>>  			if (shmdt(test) == -1)
>>  				tst_brk(TBROK | TERRNO,
>>  					 "shmdt in stat_setup()");
>> +
>> +			/* Child process quits here */
>
> Please avoid adding obvious comments like this one. The original code is
> not a good example and should be cleaned up.

Dropped :)

>
>>  			exit(0);
>> -		default:
>> -			/* save the child's pid for cleanup later */
>> -			pid_arr[i] = pid;
>>  		}
>>  	}
>>  
>> -	/* parent doesn't have to block SIGUSR1, recover the mask */
>> -	if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
>> -		tst_brk(TBROK, "parent sigprocmask");
>> -
>> -	usleep(250000);
>> +	/* Wait for all the children to attach to shared memory */
>> +	TST_CHECKPOINT_WAIT(0);
>>  }
>>  
>>  /*
>> @@ -283,11 +242,8 @@ fail:
>>   */
>>  static void stat_cleanup(void)
>>  {
>> -	int i;
>> -
>>  	/* wake up the childern so they can detach the memory and exit */
>> -	for (i = 0; i < N_ATTACH; i++)
>> -		SAFE_KILL(pid_arr[i], SIGUSR1);
>> +	TST_CHECKPOINT_WAKE2(1, N_ATTACH);
>
> We should still SAFE_WAIT() each of the processses here otherwise we
> cannot guarantee that the memory was detached and that the child really
> exitted.

Makes sense. I've added a SAFE_WAITPID() after the
TST_CHECKPOINT_WAKE2().

I'll wait for you to go through the remaining patches before sending an
update.

Thanks for the review.

Punit

>
>>  	/* remove the parent's shared memory the second time through */
>>  	if (stat_time == SECOND)
>> @@ -296,12 +252,6 @@ static void stat_cleanup(void)
>>  	stat_time++;
>>  }
>>  
>> -static void sighandler(int sig)
>> -{
>> -	if (sig != SIGUSR1)
>> -		tst_res(TFAIL, "received unexpected signal %d", sig);
>> -}
>> -
>>  /*
>>   * set_setup() - set up for the IPC_SET command with shmctl()
>>   */
>> @@ -387,4 +337,5 @@ static struct tst_test test = {
>>  	.setup = setup,
>>  	.cleanup = cleanup,
>>  	.test_all = test_hugeshmctl,
>> +	.needs_checkpoints = 1,
>>  };
>> -- 
>> 2.14.2
>> 


More information about the ltp mailing list