1 /* 2 * Copyright 2015, Sam Bobroff, IBM Corp. 3 * Licensed under GPLv2. 4 * 5 * Test the kernel's system call code to ensure that a system call 6 * made from within an active HTM transaction is aborted with the 7 * correct failure code. 8 * Conversely, ensure that a system call made from within a 9 * suspended transaction can succeed. 10 */ 11 12 #include <stdio.h> 13 #include <unistd.h> 14 #include <sys/syscall.h> 15 #include <asm/tm.h> 16 #include <sys/time.h> 17 #include <stdlib.h> 18 19 #include "utils.h" 20 #include "tm.h" 21 22 extern int getppid_tm_active(void); 23 extern int getppid_tm_suspended(void); 24 25 unsigned retries = 0; 26 27 #define TEST_DURATION 10 /* seconds */ 28 #define TM_RETRIES 100 29 30 long failure_code(void) 31 { 32 return __builtin_get_texasru() >> 24; 33 } 34 35 bool failure_is_persistent(void) 36 { 37 return (failure_code() & TM_CAUSE_PERSISTENT) == TM_CAUSE_PERSISTENT; 38 } 39 40 bool failure_is_syscall(void) 41 { 42 return (failure_code() & TM_CAUSE_SYSCALL) == TM_CAUSE_SYSCALL; 43 } 44 45 pid_t getppid_tm(bool suspend) 46 { 47 int i; 48 pid_t pid; 49 50 for (i = 0; i < TM_RETRIES; i++) { 51 if (suspend) 52 pid = getppid_tm_suspended(); 53 else 54 pid = getppid_tm_active(); 55 56 if (pid >= 0) 57 return pid; 58 59 if (failure_is_persistent()) { 60 if (failure_is_syscall()) 61 return -1; 62 63 printf("Unexpected persistent transaction failure.\n"); 64 printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n", 65 __builtin_get_texasr(), __builtin_get_tfiar()); 66 exit(-1); 67 } 68 69 retries++; 70 } 71 72 printf("Exceeded limit of %d temporary transaction failures.\n", TM_RETRIES); 73 printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n", 74 __builtin_get_texasr(), __builtin_get_tfiar()); 75 76 exit(-1); 77 } 78 79 int tm_syscall(void) 80 { 81 unsigned count = 0; 82 struct timeval end, now; 83 84 SKIP_IF(!have_htm_nosc()); 85 86 setbuf(stdout, NULL); 87 88 printf("Testing transactional syscalls for %d seconds...\n", TEST_DURATION); 89 90 gettimeofday(&end, NULL); 91 now.tv_sec = TEST_DURATION; 92 now.tv_usec = 0; 93 timeradd(&end, &now, &end); 94 95 for (count = 0; timercmp(&now, &end, <); count++) { 96 /* 97 * Test a syscall within a suspended transaction and verify 98 * that it succeeds. 99 */ 100 FAIL_IF(getppid_tm(true) == -1); /* Should succeed. */ 101 102 /* 103 * Test a syscall within an active transaction and verify that 104 * it fails with the correct failure code. 105 */ 106 FAIL_IF(getppid_tm(false) != -1); /* Should fail... */ 107 FAIL_IF(!failure_is_persistent()); /* ...persistently... */ 108 FAIL_IF(!failure_is_syscall()); /* ...with code syscall. */ 109 gettimeofday(&now, 0); 110 } 111 112 printf("%d active and suspended transactions behaved correctly.\n", count); 113 printf("(There were %d transaction retries.)\n", retries); 114 115 return 0; 116 } 117 118 int main(void) 119 { 120 return test_harness(tm_syscall, "tm_syscall"); 121 } 122