Skip to content

Commit

Permalink
Add statistics on blocked tasks
Browse files Browse the repository at this point in the history
Add functionality to see which tasks are blocked.
Add statistics variables: alive_task_count and blocked_task_count.
  • Loading branch information
nimelehin committed Dec 7, 2020
1 parent 280f07f commit ffad9d8
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 41 deletions.
44 changes: 29 additions & 15 deletions fs/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <sys/stat.h>
#include <sys/un.h>
#include "kernel/calls.h"
#include "kernel/task.h"
#include "fs/fd.h"
#include "fs/inode.h"
#include "fs/path.h"
Expand Down Expand Up @@ -409,14 +410,16 @@ int_t sys_accept(fd_t sock_fd, addr_t sockaddr_addr, addr_t sockaddr_len_addr) {

char sockaddr[sockaddr_len];
int client;
do {
sockrestart_begin_listen_wait(sock);
errno = 0;
client = accept(sock->real_fd,
sockaddr_addr != 0 ? (void *) sockaddr : NULL,
sockaddr_addr != 0 ? &sockaddr_len : NULL);
sockrestart_end_listen_wait(sock);
} while (sockrestart_should_restart_listen_wait() && errno == EINTR);
TASK_MAY_BLOCK {
do {
sockrestart_begin_listen_wait(sock);
errno = 0;
client = accept(sock->real_fd,
sockaddr_addr != 0 ? (void *) sockaddr : NULL,
sockaddr_addr != 0 ? &sockaddr_len : NULL);
sockrestart_end_listen_wait(sock);
} while (sockrestart_should_restart_listen_wait() && errno == EINTR);
}
if (client < 0)
return errno_map();

Expand Down Expand Up @@ -589,8 +592,11 @@ int_t sys_sendto(fd_t sock_fd, addr_t buffer_addr, dword_t len, dword_t flags, a
goto error;
}

ssize_t res = sendto(sock->real_fd, buffer, len, real_flags,
sockaddr_addr ? (void *) &sockaddr : NULL, sockaddr_len);
ssize_t res = 0;
TASK_MAY_BLOCK {
res = sendto(sock->real_fd, buffer, len, real_flags,
sockaddr_addr ? (void *) &sockaddr : NULL, sockaddr_len);
}
free(buffer);
if (res < 0)
return errno_map();
Expand All @@ -616,9 +622,12 @@ int_t sys_recvfrom(fd_t sock_fd, addr_t buffer_addr, dword_t len, dword_t flags,

char *buffer = malloc(len);
char sockaddr[sockaddr_len];
ssize_t res = recvfrom(sock->real_fd, buffer, len, real_flags,
sockaddr_addr != 0 ? (void *) sockaddr : NULL,
sockaddr_len_addr != 0 ? &sockaddr_len : NULL);
ssize_t res = 0;
TASK_MAY_BLOCK {
res = recvfrom(sock->real_fd, buffer, len, real_flags,
sockaddr_addr != 0 ? (void *) sockaddr : NULL,
sockaddr_len_addr != 0 ? &sockaddr_len : NULL);
}
if (res < 0) {
free(buffer);
return errno_map();
Expand Down Expand Up @@ -946,7 +955,9 @@ int_t sys_sendmsg(fd_t sock_fd, addr_t msghdr_addr, int_t flags) {
if (real_flags < 0)
goto out_free_scm;

err = sendmsg(sock->real_fd, &msg, real_flags);
TASK_MAY_BLOCK {
err = sendmsg(sock->real_fd, &msg, real_flags);
}
if (err < 0) {
err = errno_map();
goto out_free_scm;
Expand Down Expand Up @@ -1018,7 +1029,10 @@ int_t sys_recvmsg(fd_t sock_fd, addr_t msghdr_addr, int_t flags) {
msg_iov[i].iov_base = malloc(msg_iov_fake[i].len);
}

ssize_t res = recvmsg(sock->real_fd, &msg, real_flags);
ssize_t res = 0;
TASK_MAY_BLOCK {
res = recvmsg(sock->real_fd, &msg, real_flags);
}
int err = 0;
if (res < 0)
err = errno_map();
Expand Down
68 changes: 47 additions & 21 deletions kernel/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ fd_t sys_openat(fd_t at_f, addr_t path_addr, dword_t flags, mode_t_ mode) {
struct fd *at = at_fd(at_f);
if (at == NULL)
return _EBADF;
struct fd *fd = generic_openat(at, path, flags, mode);
struct fd *fd;
TASK_MAY_BLOCK {
fd = generic_openat(at, path, flags, mode);
}
if (IS_ERR(fd))
return PTR_ERR(fd);
return f_install(fd, flags);
Expand Down Expand Up @@ -241,7 +244,11 @@ dword_t sys_read(fd_t fd_no, addr_t buf_addr, dword_t size) {
char *buf = (char *) malloc(size);
if (buf == NULL)
return _ENOMEM;
int_t res = sys_read_buf(fd_no, buf, size);

int_t res = 0;
TASK_MAY_BLOCK {
res = sys_read_buf(fd_no, buf, size);
}
if (res >= 0) {
if (user_write(buf_addr, buf, res))
res = _EFAULT;
Expand Down Expand Up @@ -282,7 +289,9 @@ dword_t sys_write(fd_t fd_no, addr_t buf_addr, dword_t size) {
if (print_size > 100) print_size = 100;
STRACE("write(%d, \"%.*s\", %d)", fd_no, print_size, buf, size);

res = sys_write_buf(fd_no, buf, size);
TASK_MAY_BLOCK {
res = sys_write_buf(fd_no, buf, size);
}
out:
free(buf);
return res;
Expand Down Expand Up @@ -325,7 +334,10 @@ dword_t sys_readv(fd_t fd_no, addr_t iovec_addr, dword_t iovec_count) {
free(iovec);
return _ENOMEM;
}
ssize_t res = sys_read_buf(fd_no, buf, io_size);
ssize_t res = 0;
TASK_MAY_BLOCK {
res = sys_read_buf(fd_no, buf, io_size);
}
if (res < 0)
goto error;

Expand Down Expand Up @@ -373,8 +385,9 @@ dword_t sys_writev(fd_t fd_no, addr_t iovec_addr, dword_t iovec_count) {
STRACE(" {\"%.*s\", %u}", print_size, buf + offset, iovec[i].len);
offset += iovec[i].len;
}
res = sys_write_buf(fd_no, buf, io_size);

TASK_MAY_BLOCK {
res = sys_write_buf(fd_no, buf, io_size);
}
error:
free(buf);
free(iovec);
Expand Down Expand Up @@ -422,6 +435,7 @@ dword_t sys_pread(fd_t f, addr_t buf_addr, dword_t size, off_t_ off) {
char *buf = malloc(size+1);
if (buf == NULL)
return _ENOMEM;
task_may_block_start();
lock(&fd->lock);
ssize_t res;
if (fd->ops->pread) {
Expand All @@ -447,6 +461,7 @@ dword_t sys_pread(fd_t f, addr_t buf_addr, dword_t size, off_t_ off) {
}
out:
unlock(&fd->lock);
task_may_block_end();
free(buf);
return res;
}
Expand All @@ -461,20 +476,24 @@ dword_t sys_pwrite(fd_t f, addr_t buf_addr, dword_t size, off_t_ off) {
return _ENOMEM;
if (user_read(buf_addr, buf, size))
return _EFAULT;

lock(&fd->lock);
ssize_t res;
if (fd->ops->pwrite) {
res = fd->ops->pwrite(fd, buf, size, off);
} else {
off_t_ saved_off = fd->ops->lseek(fd, 0, LSEEK_CUR);
if ((res = fd->ops->lseek(fd, off, LSEEK_SET)) >= 0) {
res = fd->ops->write(fd, buf, size);
// This really shouldn't fail. The lseek man page lists these reasons:
// EBADF, ESPIPE: can't happen because the last lseek wouldn't have succeeded.
// EOVERFLOW: can't happen for LSEEK_SET.
// EINVAL: can't happen other than typoing LSEEK_SET, because we know saved_off is not negative.
off_t_ lseek_res = fd->ops->lseek(fd, saved_off, LSEEK_SET);
assert(lseek_res >= 0);

TASK_MAY_BLOCK {
if (fd->ops->pwrite) {
res = fd->ops->pwrite(fd, buf, size, off);
} else {
off_t_ saved_off = fd->ops->lseek(fd, 0, LSEEK_CUR);
if ((res = fd->ops->lseek(fd, off, LSEEK_SET)) >= 0) {
res = fd->ops->write(fd, buf, size);
// This really shouldn't fail. The lseek man page lists these reasons:
// EBADF, ESPIPE: can't happen because the last lseek wouldn't have succeeded.
// EOVERFLOW: can't happen for LSEEK_SET.
// EINVAL: can't happen other than typoing LSEEK_SET, because we know saved_off is not negative.
off_t_ lseek_res = fd->ops->lseek(fd, saved_off, LSEEK_SET);
assert(lseek_res >= 0);
}
}
}
unlock(&fd->lock);
Expand Down Expand Up @@ -531,7 +550,12 @@ dword_t sys_ioctl(fd_t f, dword_t cmd, dword_t arg) {
bit_clear(f, current->files->cloexec);
return 0;
}
return fd_ioctl(fd, cmd, arg);

dword_t res = 0;
TASK_MAY_BLOCK {
res = fd_ioctl(fd, cmd, arg);
}
return res;
}

dword_t sys_getcwd(addr_t buf_addr, dword_t size) {
Expand Down Expand Up @@ -953,8 +977,10 @@ dword_t sys_fsync(fd_t f) {
if (fd == NULL)
return _EBADF;
int err = 0;
if (fd->ops->fsync)
err = fd->ops->fsync(fd);
TASK_MAY_BLOCK {
if (fd->ops->fsync)
err = fd->ops->fsync(fd);
}
return err;
}

Expand Down
10 changes: 8 additions & 2 deletions kernel/poll.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ dword_t sys_select(fd_t nfds, addr_t readfds_addr, addr_t writefds_addr, addr_t
memset(writefds, 0, fdset_size);
memset(exceptfds, 0, fdset_size);
struct select_context context = {readfds, writefds, exceptfds};
int err = poll_wait(poll, select_event_callback, &context, timeout_addr == 0 ? NULL : &timeout_ts);
int err = 0;
TASK_MAY_BLOCK {
err = poll_wait(poll, select_event_callback, &context, timeout_addr == 0 ? NULL : &timeout_ts);
}
STRACE("%d end select ", current->pid);
for (fd_t i = 0; i < nfds; i++) {
if (bit_test(i, readfds) || bit_test(i, writefds) || bit_test(i, exceptfds)) {
Expand Down Expand Up @@ -191,7 +194,10 @@ dword_t sys_poll(addr_t fds, dword_t nfds, int_t timeout) {
timeout_ts.tv_sec = timeout / 1000;
timeout_ts.tv_nsec = (timeout % 1000) * 1000000;
}
int res = poll_wait(poll, poll_event_callback, &context, timeout < 0 ? NULL : &timeout_ts);
int res = 0;
TASK_MAY_BLOCK {
res = poll_wait(poll, poll_event_callback, &context, timeout < 0 ? NULL : &timeout_ts);
}
poll_destroy(poll);
for (unsigned i = 0; i < nfds; i++) {
if (files[i] != NULL)
Expand Down
6 changes: 4 additions & 2 deletions kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -636,8 +636,10 @@ int_t sys_rt_sigsuspend(addr_t mask_addr, uint_t size) {

int_t sys_pause() {
lock(&current->sighand->lock);
while (wait_for(&current->pause, &current->sighand->lock, NULL) != _EINTR)
continue;
TASK_MAY_BLOCK {
while (wait_for(&current->pause, &current->sighand->lock, NULL) != _EINTR)
continue;
}
unlock(&current->sighand->lock);
return _EINTR;
}
Expand Down
20 changes: 20 additions & 0 deletions kernel/task.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,26 @@ struct pid *pid_get_last_allocated() {
return pid_get(last_allocated_pid);
}

dword_t get_count_of_blocked_tasks() {
dword_t res = 0;
for (int pid = 0; pid <= MAX_PID; pid++) {
if (pid_get_task(pid) && pid_get_task(pid)->io_block) {
res++;
}
}
return res;
}

dword_t get_count_of_alive_tasks() {
dword_t res = 0;
for (int pid = 0; pid <= MAX_PID; pid++) {
if (pid_get_task(pid)) {
res++;
}
}
return res;
}

struct task *task_create_(struct task *parent) {
lock(&pids_lock);
do {
Expand Down
23 changes: 23 additions & 0 deletions kernel/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct task {
dword_t exit_code;
bool zombie;
bool exiting;
bool io_block;

// this structure is allocated on the stack of the parent's clone() call
struct vfork_info {
Expand Down Expand Up @@ -174,6 +175,8 @@ struct pid *pid_get(dword_t pid);
struct pid *pid_get_last_allocated(void);
struct task *pid_get_task(dword_t pid);
struct task *pid_get_task_zombie(dword_t id); // don't return null if the task exists as a zombie
dword_t get_count_of_blocked_tasks(void);
dword_t get_count_of_alive_tasks(void);

#define MAX_PID (1 << 15) // oughta be enough

Expand All @@ -189,4 +192,24 @@ extern void (*exit_hook)(struct task *task, int code);
// Will ensure that the -pid part always fits, then will fit as much of comm as possible.
void update_thread_name(void);

// To collect statics on which tasks are blocked we need to proccess areas
// of code which could block our task (e.g reads or writes). Before executing
// of functions which can block the task, we mark our task as blocked and
// unblock it after the function is executed.
__attribute__((always_inline)) inline int task_may_block_start(void) {
lock(&pids_lock);
current->io_block = 1;
unlock(&pids_lock);
return 0;
}

__attribute__((always_inline)) inline int task_may_block_end(void) {
lock(&pids_lock);
current->io_block = 0;
unlock(&pids_lock);
return 0;
}

#define TASK_MAY_BLOCK for (int i = task_may_block_start(); i < 1; task_may_block_end(), i++)

#endif
6 changes: 5 additions & 1 deletion kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,11 @@ dword_t sys_nanosleep(addr_t req_addr, addr_t rem_addr) {
req.tv_sec = req_ts.sec;
req.tv_nsec = req_ts.nsec;
struct timespec rem;
if (nanosleep(&req, &rem) < 0)
int res = 0;
TASK_MAY_BLOCK {
res = nanosleep(&req, &rem);
}
if (res < 0)
return errno_map();
if (rem_addr != 0) {
struct timespec_ rem_ts;
Expand Down

0 comments on commit ffad9d8

Please sign in to comment.