mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
Basic ^C interrupt implementation.
For testing, I made cat put itself into a new process group. This should eventually be done by sh between fork() and exec().
This commit is contained in:
parent
621217ffeb
commit
10b666f69a
Notes:
sideshowbarker
2024-07-19 18:34:25 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/10b666f69a6
11 changed files with 94 additions and 38 deletions
|
@ -40,9 +40,12 @@ static char shift_map[0x100] =
|
|||
|
||||
void Keyboard::emit(byte ch)
|
||||
{
|
||||
Key key;
|
||||
key.character = ch;
|
||||
key.modifiers = m_modifiers;
|
||||
if (m_client)
|
||||
m_client->onKeyPress(ch);
|
||||
m_queue.enqueue(ch);
|
||||
m_client->onKeyPress(key);
|
||||
m_queue.enqueue(key);
|
||||
}
|
||||
|
||||
void Keyboard::handleIRQ()
|
||||
|
@ -50,12 +53,12 @@ void Keyboard::handleIRQ()
|
|||
while (IO::in8(0x64) & 1) {
|
||||
BYTE ch = IO::in8(0x60);
|
||||
switch (ch) {
|
||||
case 0x38: m_modifiers |= MOD_ALT; break;
|
||||
case 0xB8: m_modifiers &= ~MOD_ALT; break;
|
||||
case 0x1D: m_modifiers |= MOD_CTRL; break;
|
||||
case 0x9D: m_modifiers &= ~MOD_CTRL; break;
|
||||
case 0x2A: m_modifiers |= MOD_SHIFT; break;
|
||||
case 0xAA: m_modifiers &= ~MOD_SHIFT; break;
|
||||
case 0x38: m_modifiers |= Mod_Alt; break;
|
||||
case 0xB8: m_modifiers &= ~Mod_Alt; break;
|
||||
case 0x1D: m_modifiers |= Mod_Ctrl; break;
|
||||
case 0x9D: m_modifiers &= ~Mod_Ctrl; break;
|
||||
case 0x2A: m_modifiers |= Mod_Shift; break;
|
||||
case 0xAA: m_modifiers &= ~Mod_Shift; break;
|
||||
case 0x1C: /* enter */ emit('\n'); break;
|
||||
case 0xFA: /* i8042 ack */ break;
|
||||
default:
|
||||
|
@ -75,16 +78,13 @@ void Keyboard::handleIRQ()
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!m_modifiers) {
|
||||
if (!m_modifiers)
|
||||
emit(map[ch]);
|
||||
} else if (m_modifiers & MOD_SHIFT) {
|
||||
else if (m_modifiers & Mod_Shift)
|
||||
emit(shift_map[ch]);
|
||||
} else if (m_modifiers & MOD_CTRL) {
|
||||
// FIXME: This is obviously not a good enough way to process ctrl+whatever.
|
||||
emit('^');
|
||||
else if (m_modifiers & Mod_Ctrl)
|
||||
emit(shift_map[ch]);
|
||||
}
|
||||
}
|
||||
//break;
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ ssize_t Keyboard::read(byte* buffer, size_t size)
|
|||
while (nread < size) {
|
||||
if (m_queue.isEmpty())
|
||||
break;
|
||||
buffer[nread++] = m_queue.dequeue();
|
||||
buffer[nread++] = m_queue.dequeue().character;
|
||||
}
|
||||
return nread;
|
||||
}
|
||||
|
|
|
@ -6,15 +6,25 @@
|
|||
#include <VirtualFileSystem/CharacterDevice.h>
|
||||
#include "IRQHandler.h"
|
||||
|
||||
class KeyboardClient {
|
||||
public:
|
||||
virtual ~KeyboardClient();
|
||||
virtual void onKeyPress(byte) = 0;
|
||||
};
|
||||
class KeyboardClient;
|
||||
|
||||
class Keyboard final : public IRQHandler, public CharacterDevice {
|
||||
AK_MAKE_ETERNAL
|
||||
public:
|
||||
enum Modifier {
|
||||
Mod_Alt = 0x01,
|
||||
Mod_Ctrl = 0x02,
|
||||
Mod_Shift = 0x04,
|
||||
};
|
||||
|
||||
struct Key {
|
||||
byte character { 0 };
|
||||
byte modifiers { 0 };
|
||||
bool alt() { return modifiers & Mod_Alt; }
|
||||
bool ctrl() { return modifiers & Mod_Ctrl; }
|
||||
bool shift() { return modifiers & Mod_Shift; }
|
||||
};
|
||||
|
||||
static Keyboard& the() PURE;
|
||||
|
||||
virtual ~Keyboard() override;
|
||||
|
@ -34,7 +44,12 @@ private:
|
|||
void emit(byte);
|
||||
|
||||
KeyboardClient* m_client { nullptr };
|
||||
CircularQueue<byte, 16> m_queue;
|
||||
CircularQueue<Key, 16> m_queue;
|
||||
byte m_modifiers { 0 };
|
||||
};
|
||||
|
||||
class KeyboardClient {
|
||||
public:
|
||||
virtual ~KeyboardClient();
|
||||
virtual void onKeyPress(Keyboard::Key) = 0;
|
||||
};
|
||||
|
|
|
@ -139,6 +139,15 @@ static void forEachProcess(Callback callback)
|
|||
}
|
||||
}
|
||||
|
||||
void Process::for_each_in_pgrp(pid_t pgid, Function<void(Process&)> callback)
|
||||
{
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
for (auto* process = s_processes->head(); process; process = process->next()) {
|
||||
if (process->pgid() == pgid)
|
||||
callback(*process);
|
||||
}
|
||||
}
|
||||
|
||||
Vector<Process*> Process::allProcesses()
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
|
@ -575,10 +584,10 @@ void Process::sys$exit(int status)
|
|||
switchNow();
|
||||
}
|
||||
|
||||
void Process::murder(int signal)
|
||||
void Process::send_signal(int signal, Process* sender)
|
||||
{
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
bool wasCurrent = current == this;
|
||||
bool wasCurrent = current == sender;
|
||||
set_state(Exiting);
|
||||
s_processes->remove(this);
|
||||
|
||||
|
@ -587,7 +596,7 @@ void Process::murder(int signal)
|
|||
if (wasCurrent) {
|
||||
kprintf("Current process committing suicide!\n");
|
||||
if (!scheduleNewProcess()) {
|
||||
kprintf("Process::murder: Failed to schedule a new process :(\n");
|
||||
kprintf("Process::send_signal: Failed to schedule a new process :(\n");
|
||||
HANG;
|
||||
}
|
||||
}
|
||||
|
@ -1014,9 +1023,8 @@ int Process::sys$uname(utsname* buf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Process::sys$kill(pid_t pid, int sig)
|
||||
int Process::sys$kill(pid_t pid, int signal)
|
||||
{
|
||||
(void) sig;
|
||||
if (pid == 0) {
|
||||
// FIXME: Send to same-group processes.
|
||||
ASSERT(pid != 0);
|
||||
|
@ -1030,13 +1038,8 @@ int Process::sys$kill(pid_t pid, int sig)
|
|||
auto* peer = Process::fromPID(pid);
|
||||
if (!peer)
|
||||
return -ESRCH;
|
||||
if (sig == SIGKILL) {
|
||||
peer->murder(SIGKILL);
|
||||
return 0;
|
||||
} else {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
return -1;
|
||||
peer->send_signal(signal, this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::sys$sleep(unsigned seconds)
|
||||
|
|
|
@ -73,6 +73,8 @@ public:
|
|||
void setWakeupTime(DWORD t) { m_wakeupTime = t; }
|
||||
DWORD wakeupTime() const { return m_wakeupTime; }
|
||||
|
||||
static void for_each_in_pgrp(pid_t pgid, Function<void(Process&)>);
|
||||
|
||||
static void prepForIRETToNewProcess();
|
||||
|
||||
bool tick() { ++m_ticks; return --m_ticksLeft; }
|
||||
|
@ -151,6 +153,8 @@ public:
|
|||
FileHandle* file_descriptor(size_t i) { return m_file_descriptors[i].ptr(); }
|
||||
const FileHandle* file_descriptor(size_t i) const { return m_file_descriptors[i].ptr(); }
|
||||
|
||||
void send_signal(int signal, Process* sender);
|
||||
|
||||
private:
|
||||
friend class MemoryManager;
|
||||
friend bool scheduleNewProcess();
|
||||
|
@ -211,7 +215,6 @@ private:
|
|||
pid_t m_parentPID { 0 };
|
||||
|
||||
static void notify_waiters(pid_t waitee, int exit_status, int signal);
|
||||
void murder(int signal);
|
||||
|
||||
Vector<String> m_arguments;
|
||||
Vector<String> m_initialEnvironment;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "TTY.h"
|
||||
#include "Process.h"
|
||||
|
||||
TTY::TTY(unsigned major, unsigned minor)
|
||||
: CharacterDevice(major, minor)
|
||||
|
@ -38,3 +39,16 @@ void TTY::emit(byte ch)
|
|||
{
|
||||
m_buffer.append(ch);
|
||||
}
|
||||
|
||||
void TTY::interrupt()
|
||||
{
|
||||
dbgprintf("%s: Interrupt ^C pressed!\n", ttyName().characters());
|
||||
if (pgid()) {
|
||||
dbgprintf("%s: Send SIGINT to everyone in pgrp %d\n", ttyName().characters(), pgid());
|
||||
InterruptDisabler disabler;
|
||||
Process::for_each_in_pgrp(pgid(), [this] (auto& process) {
|
||||
dbgprintf("%s: Send SIGINT to %d\n", ttyName().characters(), process.pid());
|
||||
process.send_signal(SIGINT, nullptr);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ protected:
|
|||
|
||||
virtual void onTTYWrite(byte) = 0;
|
||||
|
||||
void interrupt();
|
||||
|
||||
private:
|
||||
Vector<byte> m_buffer;
|
||||
pid_t m_pgid { 0 };
|
||||
|
|
|
@ -384,9 +384,15 @@ void VirtualConsole::on_char(byte ch, bool shouldEmit)
|
|||
set_cursor(m_cursor_row, m_cursor_column);
|
||||
}
|
||||
|
||||
void VirtualConsole::onKeyPress(byte ch)
|
||||
void VirtualConsole::onKeyPress(Keyboard::Key key)
|
||||
{
|
||||
emit(ch);
|
||||
if (key.ctrl() && key.character == 'C') {
|
||||
interrupt();
|
||||
return;
|
||||
}
|
||||
if (key.ctrl())
|
||||
emit('^');
|
||||
emit(key.character);
|
||||
}
|
||||
|
||||
void VirtualConsole::onConsoleReceive(byte ch)
|
||||
|
|
|
@ -17,7 +17,7 @@ public:
|
|||
|
||||
private:
|
||||
// ^KeyboardClient
|
||||
virtual void onKeyPress(byte) override;
|
||||
virtual void onKeyPress(Keyboard::Key) override;
|
||||
|
||||
// ^ConsoleImplementation
|
||||
virtual void onConsoleReceive(byte) override;
|
||||
|
|
|
@ -39,6 +39,11 @@ off_t lseek(int fd, off_t, int whence);
|
|||
#define WIFEXITED(status) (WTERMSIG(status) == 0)
|
||||
#define WIFSIGNALED(status) (((char) (((status) & 0x7f) + 1) >> 1) > 0)
|
||||
|
||||
#define SIGINT 2
|
||||
#define SIGKILL 9
|
||||
#define SIGSEGV 11
|
||||
#define SIGTERM 15
|
||||
|
||||
#define HOST_NAME_MAX 64
|
||||
|
||||
#define S_IFMT 0170000
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
setpgid(0, 0);
|
||||
if (argc != 2) {
|
||||
printf("usage: cat <file>\n");
|
||||
return 1;
|
||||
|
|
|
@ -157,7 +157,14 @@ static int runcmd(char* cmd)
|
|||
//printf("Exited normally with status %d\n", WEXITSTATUS(wstatus));
|
||||
} else {
|
||||
if (WIFSIGNALED(wstatus)) {
|
||||
printf("Terminated by signal %d\n", WTERMSIG(wstatus));
|
||||
switch (WTERMSIG(wstatus)) {
|
||||
case SIGINT:
|
||||
printf("Interrupted\n");
|
||||
break;
|
||||
default:
|
||||
printf("Terminated by signal %d\n", WTERMSIG(wstatus));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
printf("Exited abnormally\n");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue