Home | History | Annotate | Download | only in tm
      1 /*
      2  * Copyright 2016, Cyril Bur, IBM Corp.
      3  *
      4  * This program is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU General Public License
      6  * as published by the Free Software Foundation; either version
      7  * 2 of the License, or (at your option) any later version.
      8  *
      9  *
     10  * Test the kernel's signal frame code.
     11  *
     12  * The kernel sets up two sets of ucontexts if the signal was to be
     13  * delivered while the thread was in a transaction.
     14  * Expected behaviour is that the checkpointed state is in the user
     15  * context passed to the signal handler. The speculated state can be
     16  * accessed with the uc_link pointer.
     17  *
     18  * The rationale for this is that if TM unaware code (which linked
     19  * against TM libs) installs a signal handler it will not know of the
     20  * speculative nature of the 'live' registers and may infer the wrong
     21  * thing.
     22  */
     23 
     24 #include <stdlib.h>
     25 #include <stdio.h>
     26 #include <signal.h>
     27 #include <unistd.h>
     28 
     29 #include <altivec.h>
     30 
     31 #include "utils.h"
     32 #include "tm.h"
     33 
     34 #define MAX_ATTEMPT 500000
     35 
     36 #define NV_FPU_REGS 18
     37 
     38 long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
     39 
     40 /* Be sure there are 2x as many as there are NV FPU regs (2x18) */
     41 static double fps[] = {
     42 	 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
     43 	-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18
     44 };
     45 
     46 static sig_atomic_t fail;
     47 
     48 static void signal_usr1(int signum, siginfo_t *info, void *uc)
     49 {
     50 	int i;
     51 	ucontext_t *ucp = uc;
     52 	ucontext_t *tm_ucp = ucp->uc_link;
     53 
     54 	for (i = 0; i < NV_FPU_REGS && !fail; i++) {
     55 		fail = (ucp->uc_mcontext.fp_regs[i + 14] != fps[i]);
     56 		fail |= (tm_ucp->uc_mcontext.fp_regs[i + 14] != fps[i + NV_FPU_REGS]);
     57 		if (fail)
     58 			printf("Failed on %d FP %g or %g\n", i, ucp->uc_mcontext.fp_regs[i + 14], tm_ucp->uc_mcontext.fp_regs[i + 14]);
     59 	}
     60 }
     61 
     62 static int tm_signal_context_chk_fpu()
     63 {
     64 	struct sigaction act;
     65 	int i;
     66 	long rc;
     67 	pid_t pid = getpid();
     68 
     69 	SKIP_IF(!have_htm());
     70 
     71 	act.sa_sigaction = signal_usr1;
     72 	sigemptyset(&act.sa_mask);
     73 	act.sa_flags = SA_SIGINFO;
     74 	if (sigaction(SIGUSR1, &act, NULL) < 0) {
     75 		perror("sigaction sigusr1");
     76 		exit(1);
     77 	}
     78 
     79 	i = 0;
     80 	while (i < MAX_ATTEMPT && !fail) {
     81 		rc = tm_signal_self_context_load(pid, NULL, fps, NULL, NULL);
     82 		FAIL_IF(rc != pid);
     83 		i++;
     84 	}
     85 
     86 	return fail;
     87 }
     88 
     89 int main(void)
     90 {
     91 	return test_harness(tm_signal_context_chk_fpu, "tm_signal_context_chk_fpu");
     92 }
     93