xref: /haiku/src/tests/system/kernel/syscall_restart_test.cpp (revision 89755088d790ff4fe36f8aa77dacb2bd15507108)
1 #include <errno.h>
2 #include <netinet/in.h>
3 #include <signal.h>
4 #include <stdarg.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/socket.h>
9 
10 #include <OS.h>
11 
12 
13 enum run_mode {
14 	RUN_IGNORE_SIGNAL,
15 	RUN_HANDLE_SIGNAL,
16 	RUN_HANDLE_SIGNAL_RESTART
17 };
18 
19 
20 class Test {
21 public:
22 	Test(const char* name)
23 		: fName(name)
24 	{
25 	}
26 
27 	virtual ~Test()
28 	{
29 	}
30 
31 	bool Run(run_mode mode)
32 	{
33 		fRunMode = mode;
34 		fSignalHandlerCalled = false;
35 
36 		status_t error = Prepare();
37 		if (error != B_OK)
38 			return Error("Failed to prepare test: %s", strerror(error));
39 
40 		thread_id thread = spawn_thread(_ThreadEntry, fName, B_NORMAL_PRIORITY,
41 			this);
42 		if (thread < 0)
43 			return Error("Failed to spawn thread: %s\n", strerror(thread));
44 
45 		resume_thread(thread);
46 
47 		// ...
48 		// * interrupt without restart
49 		// * interrupt with restart
50 
51 		snooze(100000);
52 		kill(thread, SIGINT);
53 
54 		PrepareFinish();
55 
56 		status_t result;
57 		wait_for_thread(thread, &result);
58 
59 		if (result != (Interrupted() ? B_INTERRUPTED : B_OK)) {
60 			return Error("Unexpected syscall return value: %s\n",
61 				strerror(result));
62 		}
63 
64 		if ((RunMode() == RUN_IGNORE_SIGNAL) == fSignalHandlerCalled) {
65 			if (RunMode() == RUN_IGNORE_SIGNAL)
66 				return Error("Handler was called but shouldn't have been!");
67 			else
68 				return Error("Handler was not called!");
69 		}
70 
71 		return Finish(Interrupted());
72 	}
73 
74 	void Run()
75 	{
76 		printf("%s\n", fName);
77 
78 		struct {
79 			const char*	name;
80 			run_mode	mode;
81 		} tests[] = {
82 			{ "ignore signal", RUN_IGNORE_SIGNAL },
83 			{ "handle signal no restart", RUN_HANDLE_SIGNAL },
84 			{ "handle signal restart", RUN_HANDLE_SIGNAL_RESTART },
85 			{}
86 		};
87 
88 		for (int i = 0; tests[i].name != NULL; i++) {
89 			printf("  %-30s: ", tests[i].name);
90 			fflush(stdout);
91 			ClearError();
92 			if (Run(tests[i].mode))
93 				printf("ok\n");
94 			else
95 				printf("failed (%s)\n", fError);
96 
97 			Cleanup();
98 		}
99 	}
100 
101 	run_mode RunMode() const { return fRunMode; }
102 	bool Interrupted() const { return RunMode() == RUN_HANDLE_SIGNAL; }
103 	bigtime_t TimeWaited() const { return fTimeWaited; }
104 
105 protected:
106 	virtual status_t Prepare()
107 	{
108 		return B_OK;
109 	}
110 
111 	virtual status_t DoSyscall() = 0;
112 
113 	virtual void HandleSignal()
114 	{
115 	}
116 
117 	virtual void PrepareFinish()
118 	{
119 	}
120 
121 	virtual bool Finish(bool interrupted)
122 	{
123 		return true;
124 	}
125 
126 	virtual void Cleanup()
127 	{
128 	}
129 
130 	bool Error(const char* format,...)
131 	{
132 		va_list args;
133 		va_start(args, format);
134 		vsnprintf(fError, sizeof(fError), format, args);
135 		va_end(args);
136 
137 		return false;
138 	}
139 
140 	bool Check(bool condition, const char* format,...)
141 	{
142 		if (condition)
143 			return true;
144 
145 		va_list args;
146 		va_start(args, format);
147 		vsnprintf(fError, sizeof(fError), format, args);
148 		va_end(args);
149 
150 		return false;
151 	}
152 
153 	void ClearError()
154 	{
155 		fError[0] = '\0';
156 	}
157 
158 private:
159 	static status_t _ThreadEntry(void* data)
160 	{
161 		return ((Test*)data)->_TestThread();
162 	}
163 
164 	static void _SignalHandler(int signal, char* userData)
165 	{
166 		Test* self = (Test*)userData;
167 
168 		self->fSignalHandlerCalled = true;
169 		self->HandleSignal();
170 	}
171 
172 	status_t _TestThread()
173 	{
174 		// install handler
175 		struct sigaction action;
176 		if (RunMode() == RUN_IGNORE_SIGNAL)
177 			action.sa_handler = SIG_IGN;
178 		else
179 			action.sa_handler = (void (*)(int))_SignalHandler;
180 
181 		action.sa_flags = RunMode() == RUN_HANDLE_SIGNAL_RESTART
182 			? SA_RESTART : 0;
183 
184 		sigemptyset(&action.sa_mask);
185 		action.sa_userdata = this;
186 
187 		sigaction(SIGINT, &action, NULL);
188 
189 		bigtime_t startTime = system_time();
190 		status_t status = DoSyscall();
191 		fTimeWaited = system_time() - startTime;
192 
193 		return status;
194 	}
195 
196 private:
197 	const char*	fName;
198 	run_mode	fRunMode;
199 	bool		fSignalHandlerCalled;
200 	bigtime_t	fTimeWaited;
201 	char		fError[1024];
202 };
203 
204 
205 class SnoozeTest : public Test {
206 public:
207 	SnoozeTest()
208 		: Test("snooze")
209 	{
210 	}
211 
212 	virtual status_t DoSyscall()
213 	{
214 		return snooze(1000000);
215 	}
216 
217 	virtual bool Finish(bool interrupted)
218 	{
219 		if (interrupted)
220 			return Check(TimeWaited() < 200000, "waited too long");
221 
222 		return Check(TimeWaited() > 900000 && TimeWaited() < 1100000,
223 			"waited %lld us instead of 1000000 us", TimeWaited());
224 	}
225 };
226 
227 
228 class ReadTest : public Test {
229 public:
230 	ReadTest()
231 		: Test("read")
232 	{
233 	}
234 
235 	virtual status_t Prepare()
236 	{
237 		fBytesRead = -1;
238 		fFDs = (int[2]){-1, -1};
239 
240 		if (pipe(fFDs) != 0)
241 			return errno;
242 
243 		return B_OK;
244 	}
245 
246 	virtual status_t DoSyscall()
247 	{
248 		char buffer[256];
249 		fBytesRead = read(fFDs[0], buffer, sizeof(buffer));
250 
251 		return fBytesRead < 0 ? errno : B_OK;
252 	}
253 
254 	virtual void PrepareFinish()
255 	{
256 		write(fFDs[1], "Ingo", 4);
257 	}
258 
259 	virtual bool Finish(bool interrupted)
260 	{
261 		if (interrupted)
262 			return Check(fBytesRead < 0, "unexpected read");
263 
264 		return Check(fBytesRead == 4, "should have read 4 bytes, read only %ld "
265 			"bytes", fBytesRead);
266 	}
267 
268 	virtual void Cleanup()
269 	{
270 		close(fFDs[0]);
271 		close(fFDs[1]);
272 	}
273 
274 private:
275 	bigtime_t	fTimeWaited;
276 	ssize_t		fBytesRead;
277 	int			fFDs[2];
278 };
279 
280 
281 class WriteTest : public Test {
282 public:
283 	WriteTest()
284 		: Test("write")
285 	{
286 	}
287 
288 	virtual status_t Prepare()
289 	{
290 		fBytesWritten = -1;
291 		fFDs = (int[2]){-1, -1};
292 
293 		if (pipe(fFDs) != 0)
294 			return errno;
295 
296 		// fill pipe
297 		fcntl(fFDs[1], F_SETFL, O_NONBLOCK);
298 		while (write(fFDs[1], "a", 1) == 1);
299 
300 		return B_OK;
301 	}
302 
303 	virtual status_t DoSyscall()
304 	{
305 		// blocking wait
306 		fcntl(fFDs[1], F_SETFL, 0);
307 		fBytesWritten = write(fFDs[1], "Ingo", 4);
308 
309 		return fBytesWritten < 0 ? errno : B_OK;
310 	}
311 
312 	virtual void PrepareFinish()
313 	{
314 		char buffer[256];
315 		read(fFDs[0], buffer, sizeof(buffer));
316 	}
317 
318 	virtual bool Finish(bool interrupted)
319 	{
320 		if (interrupted)
321 			return Check(fBytesWritten < 0, "unexpected write");
322 
323 		return Check(fBytesWritten == 4, "should have written 4 bytes, wrote only %ld "
324 			"bytes", fBytesWritten);
325 	}
326 
327 	virtual void Cleanup()
328 	{
329 		close(fFDs[0]);
330 		close(fFDs[1]);
331 	}
332 
333 private:
334 	ssize_t		fBytesWritten;
335 	int			fFDs[2];
336 };
337 
338 
339 class AcquireSwitchSemTest : public Test {
340 public:
341 	AcquireSwitchSemTest(bool useSwitch)
342 		: Test(useSwitch ? "switch_sem" : "acquire_sem"),
343 		fSwitch(useSwitch)
344 	{
345 	}
346 
347 	virtual status_t Prepare()
348 	{
349 		fSemaphore = create_sem(0, "test sem");
350 
351 		return (fSemaphore >= 0 ? B_OK : fSemaphore);
352 	}
353 
354 	virtual status_t DoSyscall()
355 	{
356 		if (fSwitch)
357 			return switch_sem(-1, fSemaphore);
358 
359 		return acquire_sem(fSemaphore);
360 	}
361 
362 	virtual void PrepareFinish()
363 	{
364 		release_sem(fSemaphore);
365 	}
366 
367 /*
368 	virtual bool Finish(bool interrupted)
369 	{
370 //		int32 semCount = -1;
371 //		get_sem_count(fSemaphore, &semCount);
372 
373 		if (interrupted)
374 			return true;
375 
376 		return Check(fBytesWritten == 4, "should have written 4 bytes, wrote only %ld "
377 			"bytes", fBytesWritten);
378 	}
379 */
380 
381 	virtual void Cleanup()
382 	{
383 		delete_sem(fSemaphore);
384 	}
385 
386 protected:
387 	sem_id		fSemaphore;
388 	bool		fSwitch;
389 };
390 
391 
392 class AcquireSwitchSemEtcTest : public Test {
393 public:
394 	AcquireSwitchSemEtcTest(bool useSwitch)
395 		: Test(useSwitch ? "switch_sem_etc" : "acquire_sem_etc"),
396 		fSwitch(useSwitch)
397 	{
398 	}
399 
400 	virtual status_t Prepare()
401 	{
402 		fSemaphore = create_sem(0, "test sem");
403 
404 		return fSemaphore >= 0 ? B_OK : fSemaphore;
405 	}
406 
407 	virtual status_t DoSyscall()
408 	{
409 		status_t status;
410 		if (fSwitch) {
411 			status = switch_sem_etc(-1, fSemaphore, 1, B_RELATIVE_TIMEOUT,
412 				1000000);
413 		} else {
414 			status = acquire_sem_etc(fSemaphore, 1, B_RELATIVE_TIMEOUT,
415 				1000000);
416 		}
417 
418 		if (!Interrupted() && status == B_TIMED_OUT)
419 			return B_OK;
420 
421 		return status;
422 	}
423 
424 	virtual bool Finish(bool interrupted)
425 	{
426 		if (interrupted)
427 			return Check(TimeWaited() < 200000, "waited too long");
428 
429 		return Check(TimeWaited() > 900000 && TimeWaited() < 1100000,
430 			"waited %lld us instead of 1000000 us", TimeWaited());
431 	}
432 
433 	virtual void Cleanup()
434 	{
435 		delete_sem(fSemaphore);
436 	}
437 
438 protected:
439 	sem_id		fSemaphore;
440 	bool		fSwitch;
441 };
442 
443 
444 class AcceptTest : public Test {
445 public:
446 	AcceptTest()
447 		: Test("accept")
448 	{
449 	}
450 
451 	virtual status_t Prepare()
452 	{
453 		fAcceptedSocket = -1;
454 
455 		fServerSocket = socket(AF_INET, SOCK_STREAM, 0);
456 		if (fServerSocket < 0) {
457 			fprintf(stderr, "Could not open server socket: %s\n",
458 				strerror(errno));
459 			return errno;
460 		}
461 
462 		int reuse = 1;
463 		if (setsockopt(fServerSocket, SOL_SOCKET, SO_REUSEADDR, &reuse,
464 				sizeof(int)) == -1) {
465 			fprintf(stderr, "Could not make server socket reusable: %s\n",
466 				strerror(errno));
467 			return errno;
468 		}
469 
470 		memset(&fServerAddress, 0, sizeof(sockaddr_in));
471 		fServerAddress.sin_family = AF_INET;
472 		fServerAddress.sin_addr.s_addr = INADDR_LOOPBACK;
473 
474 		if (bind(fServerSocket, (struct sockaddr *)&fServerAddress,
475 				sizeof(struct sockaddr)) == -1) {
476 			fprintf(stderr, "Could not bind server socket: %s\n",
477 				strerror(errno));
478 			return errno;
479 		}
480 
481 		socklen_t length = sizeof(sockaddr_in);
482 		getsockname(fServerSocket, (sockaddr*)&fServerAddress,
483 			&length);
484 
485 		if (listen(fServerSocket, 10) == -1) {
486 			fprintf(stderr, "Could not listen on server socket: %s\n",
487 				strerror(errno));
488 			return errno;
489 		}
490 
491 		return B_OK;
492 	}
493 
494 	virtual status_t DoSyscall()
495 	{
496 		sockaddr_in clientAddress;
497 		socklen_t length = sizeof(struct sockaddr_in);
498 
499 		fAcceptedSocket = accept(fServerSocket,
500 			(struct sockaddr *)&clientAddress, &length);
501 		if (fAcceptedSocket == -1)
502 			return errno;
503 
504 		return B_OK;
505 	}
506 
507 	virtual void PrepareFinish()
508 	{
509 		if (Interrupted())
510 			return;
511 
512 		int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
513 		if (clientSocket == -1) {
514 			fprintf(stderr, "Could not open client socket: %s\n",
515 				strerror(errno));
516 			return;
517 		}
518 
519 		if (connect(clientSocket, (struct sockaddr *)&fServerAddress,
520 				sizeof(struct sockaddr)) == -1) {
521 			fprintf(stderr, "Could not connect to server socket: %s\n",
522 				strerror(errno));
523 		}
524 
525 		close(clientSocket);
526 	}
527 
528 	virtual bool Finish(bool interrupted)
529 	{
530 		if (interrupted)
531 			return Check(fAcceptedSocket < 0, "got socket");
532 
533 		return Check(fAcceptedSocket >= 0, "got no socket");
534 	}
535 
536 	virtual void Cleanup()
537 	{
538 		close(fAcceptedSocket);
539 		close(fServerSocket);
540 	}
541 
542 protected:
543 	int			fServerSocket;
544 	sockaddr_in	fServerAddress;
545 	int			fAcceptedSocket;
546 };
547 
548 
549 class ReceiveTest : public Test {
550 public:
551 	ReceiveTest()
552 		: Test("recv")
553 	{
554 	}
555 
556 	virtual status_t Prepare()
557 	{
558 		fBytesRead = -1;
559 		fAcceptedSocket = -1;
560 		fClientSocket = -1;
561 
562 		fServerSocket = socket(AF_INET, SOCK_STREAM, 0);
563 		if (fServerSocket < 0) {
564 			fprintf(stderr, "Could not open server socket: %s\n",
565 				strerror(errno));
566 			return errno;
567 		}
568 
569 		int reuse = 1;
570 		if (setsockopt(fServerSocket, SOL_SOCKET, SO_REUSEADDR, &reuse,
571 				sizeof(int)) == -1) {
572 			fprintf(stderr, "Could not make server socket reusable: %s\n",
573 				strerror(errno));
574 			return errno;
575 		}
576 
577 		memset(&fServerAddress, 0, sizeof(sockaddr_in));
578 		fServerAddress.sin_family = AF_INET;
579 		fServerAddress.sin_addr.s_addr = INADDR_LOOPBACK;
580 
581 		if (bind(fServerSocket, (struct sockaddr *)&fServerAddress,
582 				sizeof(struct sockaddr)) == -1) {
583 			fprintf(stderr, "Could not bind server socket: %s\n",
584 				strerror(errno));
585 			return errno;
586 		}
587 
588 		socklen_t length = sizeof(sockaddr_in);
589 		getsockname(fServerSocket, (sockaddr*)&fServerAddress,
590 			&length);
591 
592 		if (listen(fServerSocket, 10) == -1) {
593 			fprintf(stderr, "Could not listen on server socket: %s\n",
594 				strerror(errno));
595 			return errno;
596 		}
597 
598 		fClientSocket = socket(AF_INET, SOCK_STREAM, 0);
599 		if (fClientSocket == -1) {
600 			fprintf(stderr, "Could not open client socket: %s\n",
601 				strerror(errno));
602 			return errno;
603 		}
604 
605 		fcntl(fClientSocket, F_SETFL, O_NONBLOCK);
606 
607 		if (connect(fClientSocket, (struct sockaddr *)&fServerAddress,
608 				sizeof(struct sockaddr)) == -1) {
609 			if (errno != EINPROGRESS) {
610 				fprintf(stderr, "Could not connect to server socket: %s\n",
611 					strerror(errno));
612 				return errno;
613 			}
614 		}
615 
616 		sockaddr_in clientAddress;
617 		length = sizeof(struct sockaddr_in);
618 
619 		fAcceptedSocket = accept(fServerSocket,
620 			(struct sockaddr *)&clientAddress, &length);
621 		if (fAcceptedSocket == -1)
622 			return errno;
623 
624 		fcntl(fClientSocket, F_SETFL, 0);
625 
626 		snooze(100000);
627 
628 		return B_OK;
629 	}
630 
631 	virtual status_t DoSyscall()
632 	{
633 		char buffer[256];
634 		fBytesRead = recv(fAcceptedSocket, buffer, sizeof(buffer), 0);
635 
636 		return fBytesRead < 0 ? errno : B_OK;
637 	}
638 
639 	virtual void PrepareFinish()
640 	{
641 		write(fClientSocket, "Axel", 4);
642 	}
643 
644 	virtual bool Finish(bool interrupted)
645 	{
646 		if (interrupted)
647 			return Check(fBytesRead < 0, "unexpected read");
648 
649 		return Check(fBytesRead == 4, "should have read 4 bytes, read only %ld "
650 			"bytes", fBytesRead);
651 	}
652 
653 	virtual void Cleanup()
654 	{
655 		close(fAcceptedSocket);
656 		close(fServerSocket);
657 		close(fClientSocket);
658 	}
659 
660 protected:
661 	int			fServerSocket;
662 	sockaddr_in	fServerAddress;
663 	int			fAcceptedSocket;
664 	int			fClientSocket;
665 	ssize_t		fBytesRead;
666 };
667 
668 
669 int
670 main()
671 {
672 	Test* tests[] = {
673 		new SnoozeTest,
674 		new ReadTest,
675 		new WriteTest,
676 		new AcquireSwitchSemTest(false),
677 		new AcquireSwitchSemTest(true),
678 		new AcquireSwitchSemEtcTest(false),
679 		new AcquireSwitchSemEtcTest(true),
680 		new AcceptTest,
681 		new ReceiveTest,
682 		NULL
683 	};
684 
685 	for (int i = 0; tests[i] != NULL; i++)
686 		tests[i]->Run();
687 
688 	return 0;
689 }
690