1 /* 2 * linux and CPU test 3 * 4 * Copyright (c) 2003 Fabrice Bellard 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 #define _GNU_SOURCE 20 #include <stdarg.h> 21 #include <stdlib.h> 22 #include <stdio.h> 23 #include <unistd.h> 24 #include <fcntl.h> 25 #include <inttypes.h> 26 #include <string.h> 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <sys/wait.h> 30 #include <errno.h> 31 #include <utime.h> 32 #include <time.h> 33 #include <sys/time.h> 34 #include <sys/resource.h> 35 #include <sys/uio.h> 36 #include <sys/socket.h> 37 #include <netinet/in.h> 38 #include <arpa/inet.h> 39 #include <sched.h> 40 #include <dirent.h> 41 #include <setjmp.h> 42 #include <sys/shm.h> 43 #include <assert.h> 44 45 #define STACK_SIZE 16384 46 47 static void error1(const char *filename, int line, const char *fmt, ...) 48 { 49 va_list ap; 50 va_start(ap, fmt); 51 fprintf(stderr, "%s:%d: ", filename, line); 52 vfprintf(stderr, fmt, ap); 53 fprintf(stderr, "\n"); 54 va_end(ap); 55 exit(1); 56 } 57 58 static int __chk_error(const char *filename, int line, int ret) 59 { 60 if (ret < 0) { 61 error1(filename, line, "%m (ret=%d, errno=%d/%s)", 62 ret, errno, strerror(errno)); 63 } 64 return ret; 65 } 66 67 #define error(fmt, ...) error1(__FILE__, __LINE__, fmt, ## __VA_ARGS__) 68 69 #define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret)) 70 71 /*******************************************************/ 72 73 #define FILE_BUF_SIZE 300 74 75 static void test_file(void) 76 { 77 int fd, i, len, ret; 78 uint8_t buf[FILE_BUF_SIZE]; 79 uint8_t buf2[FILE_BUF_SIZE]; 80 uint8_t buf3[FILE_BUF_SIZE]; 81 char cur_dir[1024]; 82 struct stat st; 83 struct utimbuf tbuf; 84 struct iovec vecs[2]; 85 DIR *dir; 86 struct dirent64 *de; 87 /* TODO: make common tempdir creation for tcg tests */ 88 char template[] = "/tmp/linux-test-XXXXXX"; 89 char *tmpdir = mkdtemp(template); 90 91 assert(tmpdir); 92 93 if (getcwd(cur_dir, sizeof(cur_dir)) == NULL) 94 error("getcwd"); 95 96 chk_error(chdir(tmpdir)); 97 98 /* open/read/write/close/readv/writev/lseek */ 99 100 fd = chk_error(open("file1", O_WRONLY | O_TRUNC | O_CREAT, 0644)); 101 for(i=0;i < FILE_BUF_SIZE; i++) 102 buf[i] = i; 103 len = chk_error(write(fd, buf, FILE_BUF_SIZE / 2)); 104 if (len != (FILE_BUF_SIZE / 2)) 105 error("write"); 106 vecs[0].iov_base = buf + (FILE_BUF_SIZE / 2); 107 vecs[0].iov_len = 16; 108 vecs[1].iov_base = buf + (FILE_BUF_SIZE / 2) + 16; 109 vecs[1].iov_len = (FILE_BUF_SIZE / 2) - 16; 110 len = chk_error(writev(fd, vecs, 2)); 111 if (len != (FILE_BUF_SIZE / 2)) 112 error("writev"); 113 chk_error(close(fd)); 114 115 chk_error(rename("file1", "file2")); 116 117 fd = chk_error(open("file2", O_RDONLY)); 118 119 len = chk_error(read(fd, buf2, FILE_BUF_SIZE)); 120 if (len != FILE_BUF_SIZE) 121 error("read"); 122 if (memcmp(buf, buf2, FILE_BUF_SIZE) != 0) 123 error("memcmp"); 124 125 #define FOFFSET 16 126 ret = chk_error(lseek(fd, FOFFSET, SEEK_SET)); 127 if (ret != 16) 128 error("lseek"); 129 vecs[0].iov_base = buf3; 130 vecs[0].iov_len = 32; 131 vecs[1].iov_base = buf3 + 32; 132 vecs[1].iov_len = FILE_BUF_SIZE - FOFFSET - 32; 133 len = chk_error(readv(fd, vecs, 2)); 134 if (len != FILE_BUF_SIZE - FOFFSET) 135 error("readv"); 136 if (memcmp(buf + FOFFSET, buf3, FILE_BUF_SIZE - FOFFSET) != 0) 137 error("memcmp"); 138 139 chk_error(close(fd)); 140 141 /* access */ 142 chk_error(access("file2", R_OK)); 143 144 /* stat/chmod/utime/truncate */ 145 146 chk_error(chmod("file2", 0600)); 147 tbuf.actime = 1001; 148 tbuf.modtime = 1000; 149 chk_error(truncate("file2", 100)); 150 chk_error(utime("file2", &tbuf)); 151 chk_error(stat("file2", &st)); 152 if (st.st_size != 100) 153 error("stat size"); 154 if (!S_ISREG(st.st_mode)) 155 error("stat mode"); 156 if ((st.st_mode & 0777) != 0600) 157 error("stat mode2"); 158 if (st.st_atime != 1001 || 159 st.st_mtime != 1000) 160 error("stat time"); 161 162 chk_error(stat(tmpdir, &st)); 163 if (!S_ISDIR(st.st_mode)) 164 error("stat mode"); 165 166 /* fstat */ 167 fd = chk_error(open("file2", O_RDWR)); 168 chk_error(ftruncate(fd, 50)); 169 chk_error(fstat(fd, &st)); 170 chk_error(close(fd)); 171 172 if (st.st_size != 50) 173 error("stat size"); 174 if (!S_ISREG(st.st_mode)) 175 error("stat mode"); 176 177 /* symlink/lstat */ 178 chk_error(symlink("file2", "file3")); 179 chk_error(lstat("file3", &st)); 180 if (!S_ISLNK(st.st_mode)) 181 error("stat mode"); 182 183 /* getdents */ 184 dir = opendir(tmpdir); 185 if (!dir) 186 error("opendir"); 187 len = 0; 188 for(;;) { 189 de = readdir64(dir); 190 if (!de) 191 break; 192 if (strcmp(de->d_name, ".") != 0 && 193 strcmp(de->d_name, "..") != 0 && 194 strcmp(de->d_name, "file2") != 0 && 195 strcmp(de->d_name, "file3") != 0) 196 error("readdir"); 197 len++; 198 } 199 closedir(dir); 200 if (len != 4) 201 error("readdir"); 202 203 chk_error(unlink("file3")); 204 chk_error(unlink("file2")); 205 chk_error(chdir(cur_dir)); 206 chk_error(rmdir(tmpdir)); 207 } 208 209 static void test_fork(void) 210 { 211 int pid, status; 212 213 pid = chk_error(fork()); 214 if (pid == 0) { 215 /* child */ 216 sleep(2); 217 exit(2); 218 } 219 chk_error(waitpid(pid, &status, 0)); 220 if (!WIFEXITED(status) || WEXITSTATUS(status) != 2) 221 error("waitpid status=0x%x", status); 222 } 223 224 static void test_time(void) 225 { 226 struct timeval tv, tv2; 227 struct timespec ts, rem; 228 struct rusage rusg1, rusg2; 229 int ti, i; 230 231 chk_error(gettimeofday(&tv, NULL)); 232 rem.tv_sec = 1; 233 ts.tv_sec = 0; 234 ts.tv_nsec = 20 * 1000000; 235 chk_error(nanosleep(&ts, &rem)); 236 if (rem.tv_sec != 1) 237 error("nanosleep"); 238 chk_error(gettimeofday(&tv2, NULL)); 239 ti = tv2.tv_sec - tv.tv_sec; 240 if (ti >= 2) 241 error("gettimeofday"); 242 243 chk_error(getrusage(RUSAGE_SELF, &rusg1)); 244 for(i = 0;i < 10000; i++); 245 chk_error(getrusage(RUSAGE_SELF, &rusg2)); 246 if ((rusg2.ru_utime.tv_sec - rusg1.ru_utime.tv_sec) < 0 || 247 (rusg2.ru_stime.tv_sec - rusg1.ru_stime.tv_sec) < 0) 248 error("getrusage"); 249 } 250 251 static int server_socket(void) 252 { 253 int val, fd; 254 struct sockaddr_in sockaddr = {}; 255 256 /* server socket */ 257 fd = chk_error(socket(PF_INET, SOCK_STREAM, 0)); 258 259 val = 1; 260 chk_error(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))); 261 262 sockaddr.sin_family = AF_INET; 263 sockaddr.sin_port = htons(0); /* choose random ephemeral port) */ 264 sockaddr.sin_addr.s_addr = 0; 265 chk_error(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))); 266 chk_error(listen(fd, 1)); 267 return fd; 268 269 } 270 271 static int client_socket(uint16_t port) 272 { 273 int fd; 274 struct sockaddr_in sockaddr = {}; 275 276 /* server socket */ 277 fd = chk_error(socket(PF_INET, SOCK_STREAM, 0)); 278 sockaddr.sin_family = AF_INET; 279 sockaddr.sin_port = htons(port); 280 inet_aton("127.0.0.1", &sockaddr.sin_addr); 281 chk_error(connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))); 282 return fd; 283 } 284 285 static const char socket_msg[] = "hello socket\n"; 286 287 static void test_socket(void) 288 { 289 int server_fd, client_fd, fd, pid, ret, val; 290 struct sockaddr_in sockaddr; 291 struct sockaddr_in server_addr; 292 socklen_t len, socklen; 293 uint16_t server_port; 294 char buf[512]; 295 296 server_fd = server_socket(); 297 /* find out what port we got */ 298 socklen = sizeof(server_addr); 299 ret = getsockname(server_fd, (struct sockaddr *)&server_addr, &socklen); 300 chk_error(ret); 301 server_port = ntohs(server_addr.sin_port); 302 303 /* test a few socket options */ 304 len = sizeof(val); 305 chk_error(getsockopt(server_fd, SOL_SOCKET, SO_TYPE, &val, &len)); 306 if (val != SOCK_STREAM) 307 error("getsockopt"); 308 309 pid = chk_error(fork()); 310 if (pid == 0) { 311 client_fd = client_socket(server_port); 312 send(client_fd, socket_msg, sizeof(socket_msg), 0); 313 close(client_fd); 314 exit(0); 315 } 316 len = sizeof(sockaddr); 317 fd = chk_error(accept(server_fd, (struct sockaddr *)&sockaddr, &len)); 318 319 ret = chk_error(recv(fd, buf, sizeof(buf), 0)); 320 if (ret != sizeof(socket_msg)) 321 error("recv"); 322 if (memcmp(buf, socket_msg, sizeof(socket_msg)) != 0) 323 error("socket_msg"); 324 chk_error(close(fd)); 325 chk_error(close(server_fd)); 326 } 327 328 #define WCOUNT_MAX 512 329 330 static void test_pipe(void) 331 { 332 fd_set rfds, wfds; 333 int fds[2], fd_max, ret; 334 uint8_t ch; 335 int wcount, rcount; 336 337 chk_error(pipe(fds)); 338 chk_error(fcntl(fds[0], F_SETFL, O_NONBLOCK)); 339 chk_error(fcntl(fds[1], F_SETFL, O_NONBLOCK)); 340 wcount = 0; 341 rcount = 0; 342 for(;;) { 343 FD_ZERO(&rfds); 344 fd_max = fds[0]; 345 FD_SET(fds[0], &rfds); 346 347 FD_ZERO(&wfds); 348 FD_SET(fds[1], &wfds); 349 if (fds[1] > fd_max) 350 fd_max = fds[1]; 351 352 ret = chk_error(select(fd_max + 1, &rfds, &wfds, NULL, NULL)); 353 if (ret > 0) { 354 if (FD_ISSET(fds[0], &rfds)) { 355 chk_error(read(fds[0], &ch, 1)); 356 rcount++; 357 if (rcount >= WCOUNT_MAX) { 358 break; 359 } 360 } 361 if (FD_ISSET(fds[1], &wfds)) { 362 ch = 'a'; 363 chk_error(write(fds[1], &ch, 1)); 364 wcount++; 365 if (wcount >= WCOUNT_MAX) { 366 break; 367 } 368 } 369 } 370 } 371 chk_error(close(fds[0])); 372 chk_error(close(fds[1])); 373 } 374 375 static int thread1_res; 376 static int thread2_res; 377 378 static int thread1_func(void *arg) 379 { 380 int i; 381 for(i=0;i<5;i++) { 382 thread1_res++; 383 usleep(10 * 1000); 384 } 385 return 0; 386 } 387 388 static int thread2_func(void *arg) 389 { 390 int i; 391 for(i=0;i<6;i++) { 392 thread2_res++; 393 usleep(10 * 1000); 394 } 395 return 0; 396 } 397 398 static void wait_for_child(pid_t pid) 399 { 400 int status; 401 chk_error(waitpid(pid, &status, 0)); 402 } 403 404 /* For test_clone we must match the clone flags used by glibc, see 405 * CLONE_THREAD_FLAGS in the QEMU source code. 406 */ 407 static void test_clone(void) 408 { 409 uint8_t *stack1, *stack2; 410 pid_t pid1, pid2; 411 412 stack1 = malloc(STACK_SIZE); 413 pid1 = chk_error(clone(thread1_func, stack1 + STACK_SIZE, 414 CLONE_VM | CLONE_FS | CLONE_FILES | 415 CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM, 416 "hello1")); 417 418 stack2 = malloc(STACK_SIZE); 419 pid2 = chk_error(clone(thread2_func, stack2 + STACK_SIZE, 420 CLONE_VM | CLONE_FS | CLONE_FILES | 421 CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM, 422 "hello2")); 423 424 wait_for_child(pid1); 425 free(stack1); 426 wait_for_child(pid2); 427 free(stack2); 428 429 if (thread1_res != 5 || 430 thread2_res != 6) 431 error("clone"); 432 } 433 434 /***********************************/ 435 436 volatile int alarm_count; 437 jmp_buf jmp_env; 438 439 static void sig_alarm(int sig) 440 { 441 if (sig != SIGALRM) 442 error("signal"); 443 alarm_count++; 444 } 445 446 static void sig_segv(int sig, siginfo_t *info, void *puc) 447 { 448 if (sig != SIGSEGV) 449 error("signal"); 450 longjmp(jmp_env, 1); 451 } 452 453 static void test_signal(void) 454 { 455 struct sigaction act; 456 struct itimerval it, oit; 457 458 /* timer test */ 459 460 alarm_count = 0; 461 462 act.sa_handler = sig_alarm; 463 sigemptyset(&act.sa_mask); 464 act.sa_flags = 0; 465 chk_error(sigaction(SIGALRM, &act, NULL)); 466 467 it.it_interval.tv_sec = 0; 468 it.it_interval.tv_usec = 10 * 1000; 469 it.it_value.tv_sec = 0; 470 it.it_value.tv_usec = 10 * 1000; 471 chk_error(setitimer(ITIMER_REAL, &it, NULL)); 472 chk_error(getitimer(ITIMER_REAL, &oit)); 473 474 while (alarm_count < 5) { 475 usleep(10 * 1000); 476 getitimer(ITIMER_REAL, &oit); 477 } 478 479 it.it_interval.tv_sec = 0; 480 it.it_interval.tv_usec = 0; 481 it.it_value.tv_sec = 0; 482 it.it_value.tv_usec = 0; 483 memset(&oit, 0xff, sizeof(oit)); 484 chk_error(setitimer(ITIMER_REAL, &it, &oit)); 485 486 /* SIGSEGV test */ 487 act.sa_sigaction = sig_segv; 488 sigemptyset(&act.sa_mask); 489 act.sa_flags = SA_SIGINFO; 490 chk_error(sigaction(SIGSEGV, &act, NULL)); 491 if (setjmp(jmp_env) == 0) { 492 /* 493 * clang requires volatile or it will turn this into a 494 * call to abort() instead of forcing a SIGSEGV. 495 */ 496 *(volatile uint8_t *)0 = 0; 497 } 498 499 act.sa_handler = SIG_DFL; 500 sigemptyset(&act.sa_mask); 501 act.sa_flags = 0; 502 chk_error(sigaction(SIGSEGV, &act, NULL)); 503 504 if (sigaction(SIGKILL, &act, NULL) == 0) { 505 error("sigaction(SIGKILL, &act, NULL) must not succeed"); 506 } 507 if (sigaction(SIGSTOP, &act, NULL) == 0) { 508 error("sigaction(SIGSTOP, &act, NULL) must not succeed"); 509 } 510 chk_error(sigaction(SIGKILL, NULL, &act)); 511 chk_error(sigaction(SIGSTOP, NULL, &act)); 512 } 513 514 #define SHM_SIZE 32768 515 516 static void test_shm(void) 517 { 518 void *ptr; 519 int shmid; 520 521 shmid = chk_error(shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0777)); 522 ptr = shmat(shmid, NULL, 0); 523 if (ptr == (void *)-1) { 524 error("shmat"); 525 } 526 527 memset(ptr, 0, SHM_SIZE); 528 529 chk_error(shmctl(shmid, IPC_RMID, 0)); 530 chk_error(shmdt(ptr)); 531 } 532 533 int main(int argc, char **argv) 534 { 535 test_file(); 536 test_pipe(); 537 test_fork(); 538 test_time(); 539 test_socket(); 540 541 if (argc > 1) { 542 printf("test_clone still considered buggy\n"); 543 test_clone(); 544 } 545 546 test_signal(); 547 test_shm(); 548 return 0; 549 } 550