mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-29 21:58:20 +00:00
jobctl/tty: foreground/background and send sighup on unregister
This commit is contained in:
@@ -14,5 +14,7 @@ pid_t jobctl_getsid(proc_t *proc);
|
||||
void jobctl_setctty(proc_t *proc, void *ctty);
|
||||
void *jobctl_getctty(proc_t *proc);
|
||||
int jobctl_signal(proc_t *proc, int signal);
|
||||
proc_t *jobctl_getforeground(proc_t *proc);
|
||||
int jobctl_setforeground(proc_t *session, proc_t *pgrp);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,8 @@ typedef struct {
|
||||
int minor;
|
||||
winsize_t winsize;
|
||||
vnode_t *mastervnode;
|
||||
spinlock_t sessionlock;
|
||||
struct proc_t *session;
|
||||
} tty_t;
|
||||
|
||||
void tty_init();
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
#include <kernel/net.h>
|
||||
#include <kernel/sock.h>
|
||||
#include <ringbuffer.h>
|
||||
|
||||
#define WORKER_COUNT 8
|
||||
#define WORKER_BUFFER_SIZE (64 * 1024)
|
||||
#define WORKER_INTERNAL_BUFFER_SIZE 2048
|
||||
// MSS will be min(MSS_LIMIT, mtu - sizeof(ipv4header_t) - sizeof(tcpheader_t))
|
||||
#define MSS_LIMIT = (WORKER_INTERNAL_BUFFER_SIZE - sizeof(tcpheader_t))
|
||||
|
||||
typedef struct {
|
||||
spinlock_t lock;
|
||||
semaphore_t semaphore;
|
||||
// format:
|
||||
// ipv4 pseudo header
|
||||
// tcp packet
|
||||
ringbuffer_t ringbuffer;
|
||||
} tcpworker_t;
|
||||
|
||||
static tcpworker_t worker[WORKER_COUNT];
|
||||
static uint64_t currentworker;
|
||||
|
||||
typedef struct {
|
||||
uint32_t peer;
|
||||
uint16_t peerport;
|
||||
uint16_t localport;
|
||||
} connkey_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t srcport;
|
||||
uint16_t dstport;
|
||||
uint32_t seq;
|
||||
uint32_t ack;
|
||||
uint8_t dataoffset;
|
||||
uint8_t control;
|
||||
uint16_t window;
|
||||
uint16_t checksum;
|
||||
uint16_t urgentptr;
|
||||
} __attribute__((packed)) tcpheader_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t source;
|
||||
uint32_t dest;
|
||||
uint8_t zero;
|
||||
uint8_t protocol;
|
||||
uint16_t length;
|
||||
} __attribute__((packed)) ipv4pseudoheader_t;
|
||||
|
||||
#define TCP_STATE_LISTEN 0 // listening for connections
|
||||
#define TCP_STATE_SYNSENT 1 // sent a connection request
|
||||
#define TCP_STATE_SYNRECEIVED 2 // received a connection request, waiting for ACK
|
||||
#define TCP_STATE_ESTABILISHED 3 // got connection ACK, connection is oppen
|
||||
#define TCP_STATE_FINWAIT1 4 // waiting for connection termination from peer or an ack for the already sent FIN
|
||||
#define TCP_STATE_FINWAIT2 5 // waiting for connection termination from peer
|
||||
#define TCP_STATE_CLOSEWAIT 7 // waiting for a termination request from local user
|
||||
#define TCP_STATE_CLOSING 8 // waiting for termination ack
|
||||
|
||||
typedef struct {
|
||||
spinlock_t lock;
|
||||
int state;
|
||||
ringbuffer_t ringbuffer;
|
||||
|
||||
uint32_t snduna;
|
||||
uint32_t sndnext;
|
||||
uint32_t sndwindow;
|
||||
uint32_t sndurgent;
|
||||
uint32_t sndseqwl;
|
||||
uint32_t sndackwl;
|
||||
uint32_t iss;
|
||||
|
||||
uint32_t rcvnext;
|
||||
uint32_t rcvwindow;
|
||||
uint32_t rcvurgent;
|
||||
uint32_t irs;
|
||||
} tcb_t;
|
||||
|
||||
// TODO dpc:
|
||||
// construct ipv4header
|
||||
// calculate checksum
|
||||
// check against WORKER_INTERNAL_BUFFER_SIZE
|
||||
|
||||
// ran in DPC context
|
||||
void tcp_process(netdev_t *netdev, void *buffer, ipv4frame_t *ipv4frame) {
|
||||
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) static void tcp_worker() {
|
||||
tcpworker_t *self = _cpu()->thread->kernelarg;
|
||||
ipv4pseudoheader_t ipv4;
|
||||
uint8_t buffer[WORKER_INTERNAL_BUFFER_SIZE];
|
||||
|
||||
for (;;) {
|
||||
// wait for a task
|
||||
semaphore_wait(&self->semaphore, false);
|
||||
|
||||
interrupt_set(false);
|
||||
spinlock_acquire(&self->lock);
|
||||
|
||||
// read pseudo ipv4 header constructed by tcp_process
|
||||
// the checksum has already been calculated by it
|
||||
__assert(ringbuffer_read(&self->ringbuffer, &ipv4, sizeof(ipv4pseudoheader_t)) == sizeof(ipv4pseudoheader_t));
|
||||
|
||||
// and then the actual tcp packet
|
||||
__assert(ringbuffer_read(&self->ringbuffer, buffer, ipv4.length) == ipv4.length);
|
||||
|
||||
spinlock_release(&self->lock);
|
||||
interrupt_set(true);
|
||||
|
||||
tcpheader_t *tcpheader = buffer;
|
||||
|
||||
// TODO get tcb of connection (if any)
|
||||
}
|
||||
}
|
||||
|
||||
void tcp_init() {
|
||||
for (int i = 0; i < WORKER_COUNT; ++i) {
|
||||
// initialize worker threads
|
||||
|
||||
SPINLOCK_INIT(worker[i].lock);
|
||||
SEMAPHORE_INIT(&worker[i].semaphore, 0);
|
||||
__assert(ringbuffer_init(&worker[i].ringbuffer, WORKER_BUFFER_SIZE) == 0);
|
||||
thread_t *thread = sched_newthread(tcp_worker, PAGE_SIZE * 3, 0, NULL, NULL);
|
||||
__assert(thread);
|
||||
thread->kernelarg = &worker[i];
|
||||
sched_queue(thread);
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,6 @@ static int close(int minor, int flags) {
|
||||
if (pty == NULL)
|
||||
return ENODEV;
|
||||
|
||||
// TODO do tty cleanup stuff like sending sighup
|
||||
bool intstatus = interrupt_set(false);
|
||||
spinlock_acquire(&pty->lock);
|
||||
pty->hangup = true;
|
||||
|
||||
@@ -376,6 +376,7 @@ tty_t *tty_create(char *name, ttydevicewritefn_t writefn, ttyinactivefn_t inacti
|
||||
strcpy(tty->name, name);
|
||||
MUTEX_INIT(&tty->readmutex);
|
||||
MUTEX_INIT(&tty->writemutex);
|
||||
SPINLOCK_INIT(tty->sessionlock);
|
||||
|
||||
tty->termios.c_iflag = ICRNL;
|
||||
tty->termios.c_oflag = ONLCR;
|
||||
@@ -412,6 +413,22 @@ tty_t *tty_create(char *name, ttydevicewritefn_t writefn, ttyinactivefn_t inacti
|
||||
|
||||
void tty_unregister(tty_t *tty) {
|
||||
devfs_remove(tty->name, DEV_MAJOR_TTY, tty->minor);
|
||||
bool intstatus = interrupt_set(false);
|
||||
spinlock_acquire(&tty->sessionlock);
|
||||
proc_t *session = tty->session;
|
||||
if (session) {
|
||||
PROC_HOLD(session);
|
||||
}
|
||||
spinlock_release(&tty->sessionlock);
|
||||
interrupt_set(intstatus);
|
||||
|
||||
if (session) {
|
||||
proc_t *foreground = jobctl_getforeground(session);
|
||||
jobctl_signal(foreground, SIGHUP);
|
||||
|
||||
PROC_RELEASE(session);
|
||||
PROC_RELEASE(foreground);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+78
-2
@@ -49,11 +49,19 @@ void jobctl_setctty(proc_t *proc, void *_ctty) {
|
||||
if (tty == NULL && proc->session.controllingtty) {
|
||||
unholdtty = proc->session.controllingtty;
|
||||
proc->session.controllingtty = NULL;
|
||||
spinlock_acquire(&unholdtty->sessionlock);
|
||||
unholdtty->session = NULL;
|
||||
spinlock_release(&unholdtty->sessionlock);
|
||||
}
|
||||
|
||||
if (tty && proc->session.controllingtty == NULL) {
|
||||
VOP_HOLD(tty->mastervnode);
|
||||
proc->session.controllingtty = tty;
|
||||
spinlock_acquire(&tty->sessionlock);
|
||||
if (tty->session == NULL) {
|
||||
VOP_HOLD(tty->mastervnode);
|
||||
proc->session.controllingtty = tty;
|
||||
tty->session = proc;
|
||||
}
|
||||
spinlock_release(&tty->sessionlock);
|
||||
}
|
||||
|
||||
leave:
|
||||
@@ -226,6 +234,8 @@ void jobctl_detach(proc_t *proc) {
|
||||
// called on process exit (when the last userland thread is exiting)
|
||||
proc_t *unholdpgrp = NULL;
|
||||
proc_t *unholdsession = NULL;
|
||||
proc_t *foreground = NULL;
|
||||
|
||||
bool intstatus = interrupt_set(false);
|
||||
spinlock_acquire(&proc->jobctllock);
|
||||
|
||||
@@ -238,6 +248,10 @@ void jobctl_detach(proc_t *proc) {
|
||||
if (proc->session.leader) {
|
||||
unholdsession = proc->session.leader;
|
||||
proc->session.leader = NULL;
|
||||
} else {
|
||||
// send sighup and sigcont to all processes in the foreground group
|
||||
foreground = proc->session.foreground ? proc->session.foreground : proc;
|
||||
PROC_HOLD(foreground);
|
||||
}
|
||||
|
||||
spinlock_release(&proc->jobctllock);
|
||||
@@ -249,6 +263,11 @@ void jobctl_detach(proc_t *proc) {
|
||||
|
||||
if (unholdsession) {
|
||||
PROC_RELEASE(unholdsession);
|
||||
} else {
|
||||
jobctl_setctty(proc, NULL);
|
||||
jobctl_signal(foreground, SIGHUP);
|
||||
jobctl_signal(foreground, SIGCONT);
|
||||
PROC_RELEASE(foreground);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,6 +291,63 @@ void jobctl_addproc(proc_t *parent, proc_t *proc) {
|
||||
interrupt_set(intstatus);
|
||||
}
|
||||
|
||||
proc_t *jobctl_getforeground(proc_t *proc) {
|
||||
proc_t *foreground = NULL;
|
||||
|
||||
bool intstatus = interrupt_set(false);
|
||||
spinlock_acquire(&proc->jobctllock);
|
||||
|
||||
if (proc->session.leader)
|
||||
goto leave;
|
||||
|
||||
foreground = proc->session.foreground ? proc->session.foreground : proc;
|
||||
PROC_HOLD(foreground);
|
||||
|
||||
leave:
|
||||
spinlock_release(&proc->jobctllock);
|
||||
interrupt_set(intstatus);
|
||||
|
||||
return foreground;
|
||||
}
|
||||
int jobctl_setforeground(proc_t *session, proc_t *pgrp) {
|
||||
proc_t *unhold = NULL;
|
||||
int error = 0;
|
||||
|
||||
bool intstatus = interrupt_set(false);
|
||||
spinlock_acquire(&session->jobctllock);
|
||||
if (session->session.leader) {
|
||||
error = EINVAL;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (session != pgrp) {
|
||||
spinlock_acquire(&pgrp->jobctllock);
|
||||
if (pgrp->pgrp.leader || pgrp->session.leader != session) {
|
||||
error = EPERM;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
if (session->session.foreground)
|
||||
unhold = session->session.foreground;
|
||||
|
||||
session->session.foreground = pgrp;
|
||||
PROC_HOLD(pgrp);
|
||||
|
||||
leave:
|
||||
if (session != pgrp)
|
||||
spinlock_release(&pgrp->jobctllock);
|
||||
|
||||
spinlock_release(&session->jobctllock);
|
||||
interrupt_set(intstatus);
|
||||
|
||||
if (unhold) {
|
||||
PROC_RELEASE(unhold);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void jobctl_procremove(proc_t *proc) {
|
||||
// called after all refcounts to a proc are released
|
||||
// cleans up session stuff
|
||||
|
||||
Reference in New Issue
Block a user