1 /* 2 * Copyright (c) 2015 Eugene Syromyatnikov <evgsyr (at) gmail.com> 3 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv (at) altlinux.org> 4 * Copyright (c) 2015-2017 The strace developers. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /** 31 * @file 32 * This test burns some CPU cycles in user space and kernel space in order to 33 * get some non-zero values returned by times(2). 34 */ 35 36 #include "tests.h" 37 #include <sched.h> 38 #include <stdio.h> 39 #include <time.h> 40 #include <unistd.h> 41 42 #include <asm/unistd.h> 43 #include <sys/times.h> 44 #include <sys/wait.h> 45 46 enum { 47 NUM_USER_ITERS = 1000000, 48 PARENT_CPUTIME_LIMIT_NSEC = 200000000, 49 CHILD_CPUTIME_LIMIT_NSEC = 300000000 50 }; 51 52 int 53 main(void) 54 { 55 struct timespec ts; 56 volatile int dummy = 0; 57 int i = 0; 58 59 pid_t pid = fork(); 60 if (pid < 0) 61 perror_msg_and_fail("fork"); 62 63 const long cputime_limit = 64 pid ? PARENT_CPUTIME_LIMIT_NSEC : CHILD_CPUTIME_LIMIT_NSEC; 65 66 /* Enjoying my user time */ 67 while (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0) { 68 if (ts.tv_sec || ts.tv_nsec >= cputime_limit) 69 break; 70 71 if (i && !(ts.tv_sec || ts.tv_nsec)) 72 error_msg_and_skip("clock_gettime(CLOCK_PROCESS_CPUTIME_ID, {0, 0})"); 73 74 for (i = 0; i < NUM_USER_ITERS; ++i) 75 ++dummy; 76 } 77 78 /* Enjoying my system time */ 79 while (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0) { 80 if (ts.tv_sec || ts.tv_nsec >= cputime_limit * 2) 81 break; 82 83 sched_yield(); 84 } 85 86 if (pid == 0) { 87 return 0; 88 } else { 89 wait(NULL); 90 } 91 92 struct tms tbuf; 93 unsigned long long llres; 94 95 /* 96 * On systems where user's and kernel's long types are the same, 97 * prefer direct times syscall over libc's times function because 98 * the latter is more prone to return value truncation. 99 */ 100 #undef USE_LIBC_SYSCALL 101 #if defined __NR_times && \ 102 !defined(LINUX_MIPSN32) && \ 103 !(defined __x86_64__ && defined __ILP32__) 104 # define USE_LIBC_SYSCALL 1 105 #endif 106 107 #if defined USE_LIBC_SYSCALL 108 long res = syscall(__NR_times, &tbuf); 109 110 if (-1L == res) 111 perror_msg_and_skip("times"); 112 else 113 llres = (unsigned long) res; 114 #elif defined __NR_times && defined __x86_64__ && defined __ILP32__ 115 register long arg asm("rdi") = (long) &tbuf; 116 asm volatile("syscall\n\t" 117 : "=a"(llres) 118 : "0"(__NR_times), "r"(arg) 119 : "memory", "cc", "r11", "cx"); 120 if (llres > 0xfffffffffffff000) 121 return 77; 122 #else 123 clock_t res = times(&tbuf); 124 125 if ((clock_t) -1 == res) 126 perror_msg_and_skip("times"); 127 if (sizeof(res) < sizeof(unsigned long long)) 128 llres = (unsigned long) res; 129 else 130 llres = res; 131 #endif 132 133 printf("times({tms_utime=%llu, tms_stime=%llu, ", 134 (unsigned long long) tbuf.tms_utime, 135 (unsigned long long) tbuf.tms_stime); 136 printf("tms_cutime=%llu, tms_cstime=%llu}) = %llu\n", 137 (unsigned long long) tbuf.tms_cutime, 138 (unsigned long long) tbuf.tms_cstime, 139 llres); 140 puts("+++ exited with 0 +++"); 141 142 return 0; 143 } 144