Kernel: Userspace signal handlers are now called one at a time
I added a syscall for telling the kernel when signal execution has finished. We should send a random hash or id to the signal trampoline that we would include in the syscall, so validity of signal exit can be confirmed.
This commit is contained in:
		
							parent
							
								
									7391d91317
								
							
						
					
					
						commit
						adb14ba373
					
				|  | @ -46,6 +46,7 @@ set(KERNEL_SOURCES | |||
| 	kernel/Scheduler.cpp | ||||
| 	kernel/Semaphore.cpp | ||||
| 	kernel/Serial.cpp | ||||
| 	kernel/Signal.cpp | ||||
| 	kernel/SpinLock.cpp | ||||
| 	kernel/SSP.cpp | ||||
| 	kernel/Storage/ATABus.cpp | ||||
|  |  | |||
|  | @ -24,6 +24,9 @@ signal_trampoline: | |||
| 	movq 120(%rsp), %rax | ||||
| 	call *%rax | ||||
| 
 | ||||
| 	movq 128(%rsp), %rdi | ||||
| 	call signal_done | ||||
| 
 | ||||
| 	popq %r15 | ||||
| 	popq %r14 | ||||
| 	popq %r13 | ||||
|  |  | |||
|  | @ -38,6 +38,7 @@ namespace Kernel | |||
| 		void setup_exec(); | ||||
| 
 | ||||
| 		bool has_signal_to_execute() const; | ||||
| 		void set_signal_done(int signal); | ||||
| 		void handle_next_signal(); | ||||
| 		void handle_signal(int signal, uintptr_t& return_rsp, uintptr_t& return_rip); | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,8 @@ | |||
| #include <sys/syscall.h> | ||||
| #include <kernel/Syscall.h> | ||||
| 
 | ||||
| extern "C" __attribute__((section(".userspace"))) | ||||
| void signal_done(int signal) | ||||
| { | ||||
| 	Kernel::syscall(SYS_SIGNAL_DONE, signal); | ||||
| } | ||||
|  | @ -22,6 +22,12 @@ namespace Kernel | |||
| 	{ | ||||
| 		Thread::current().set_in_syscall(true); | ||||
| 
 | ||||
| 		if (syscall == SYS_SIGNAL_DONE) | ||||
| 		{ | ||||
| 			Thread::current().set_signal_done((int)arg1); | ||||
| 			return 0; | ||||
| 		} | ||||
| 
 | ||||
| 		asm volatile("sti"); | ||||
| 
 | ||||
| 		(void)arg1; | ||||
|  | @ -149,6 +155,9 @@ namespace Kernel | |||
| 		case SYS_SIGNAL: | ||||
| 			ret = Process::current().sys_signal((int)arg1, (void (*)(int))arg2); | ||||
| 			break; | ||||
| 		case SYS_SIGNAL_DONE: | ||||
| 			// Handled above
 | ||||
| 			ASSERT_NOT_REACHED(); | ||||
| 		default: | ||||
| 			dwarnln("Unknown syscall {}", syscall); | ||||
| 			break; | ||||
|  |  | |||
|  | @ -150,6 +150,19 @@ namespace Kernel | |||
| 		return !m_signal_queue.empty() && !m_handling_signal; | ||||
| 	} | ||||
| 
 | ||||
| 	void Thread::set_signal_done(int signal) | ||||
| 	{ | ||||
| 		ASSERT(!interrupts_enabled()); | ||||
| 		if (!m_handling_signal) | ||||
| 			derrorln("set_signal_done called while not handling singal"); | ||||
| 		else if (m_signal_queue.empty()) | ||||
| 			derrorln("set_signal_done called and there are no signals in queue"); | ||||
| 		else if (m_signal_queue.front() != signal) | ||||
| 			derrorln("set_signal_done called with wrong signal"); | ||||
| 		else | ||||
| 			m_signal_queue.pop(); | ||||
| 	} | ||||
| 
 | ||||
| 	void Thread::handle_next_signal() | ||||
| 	{ | ||||
| 		ASSERT(!interrupts_enabled()); | ||||
|  | @ -167,8 +180,6 @@ namespace Kernel | |||
| 
 | ||||
| 		vaddr_t signal_handler = process().m_signal_handlers[signal]; | ||||
| 
 | ||||
| 		m_handling_signal = true; | ||||
| 
 | ||||
| 		// Skip masked and ignored signals
 | ||||
| 		if (m_signal_mask & (1ull << signal)) | ||||
| 			; | ||||
|  | @ -176,13 +187,15 @@ namespace Kernel | |||
| 			; | ||||
| 		else if (signal_handler != (vaddr_t)SIG_DFL) | ||||
| 		{ | ||||
| 			// call userspace signal handlers
 | ||||
| 			// FIXME: signal trampoline should take a hash etc
 | ||||
| 			//        to only allow marking signals done from it
 | ||||
| 			m_handling_signal = true; | ||||
| 			write_to_stack(return_rsp, return_rip); | ||||
| 			write_to_stack(return_rsp, signal); | ||||
| 			write_to_stack(return_rsp, signal_handler); | ||||
| 			return_rip = (uintptr_t)signal_trampoline; | ||||
| 
 | ||||
| 			// FIXME: we should only mark this signal as done when
 | ||||
| 			//        handler returns
 | ||||
| 			return; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
|  | @ -241,7 +254,6 @@ namespace Kernel | |||
| 		} | ||||
| 
 | ||||
| 		m_signal_queue.pop(); | ||||
| 		m_handling_signal = false; | ||||
| 	} | ||||
| 
 | ||||
| 	void Thread::validate_stack() const | ||||
|  |  | |||
|  | @ -44,6 +44,7 @@ __BEGIN_DECLS | |||
| #define SYS_RAISE 37 | ||||
| #define SYS_KILL 38 | ||||
| #define SYS_SIGNAL 39 | ||||
| #define SYS_SIGNAL_DONE 40 | ||||
| 
 | ||||
| __END_DECLS | ||||
| 
 | ||||
|  |  | |||
|  | @ -286,6 +286,9 @@ long syscall(long syscall, ...) | |||
| 			ret = Kernel::syscall(SYS_SIGNAL, signal, (uintptr_t)handler); | ||||
| 			break; | ||||
| 		} | ||||
| 		case SYS_SIGNAL_DONE: | ||||
| 			// Should not be called by an user
 | ||||
| 			// fall through
 | ||||
| 		default: | ||||
| 			puts("LibC: Unhandeled syscall"); | ||||
| 			ret = -ENOSYS; | ||||
|  |  | |||
|  | @ -281,6 +281,39 @@ int execute_command(BAN::Vector<BAN::String>& args) | |||
| 			return 1; | ||||
| 		} | ||||
| 	} | ||||
| 	else if (args.front() == "signal-test"sv) | ||||
| 	{ | ||||
| 		pid_t pid = fork(); | ||||
| 		if (pid == 0) | ||||
| 		{ | ||||
| 			if (signal(SIGSEGV, [](int) { printf("SIGSEGV\n"); }) == SIG_ERR) | ||||
| 			{ | ||||
| 				perror("signal"); | ||||
| 				exit(1); | ||||
| 			} | ||||
| 			printf("child\n"); | ||||
| 			for (;;); | ||||
| 		} | ||||
| 		if (pid == -1) | ||||
| 		{ | ||||
| 			perror("fork"); | ||||
| 			return 1; | ||||
| 		} | ||||
| 
 | ||||
| 		sleep(1); | ||||
| 		if (kill(pid, SIGSEGV) == -1) | ||||
| 		{ | ||||
| 			perror("kill"); | ||||
| 			return 1; | ||||
| 		} | ||||
| 
 | ||||
| 		sleep(1); | ||||
| 		if (kill(pid, SIGTERM) == -1) | ||||
| 		{ | ||||
| 			perror("kill"); | ||||
| 			return 1; | ||||
| 		} | ||||
| 	} | ||||
| 	else if (args.front() == "cd"sv) | ||||
| 	{ | ||||
| 		if (args.size() > 2) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue