Compare commits
No commits in common. "3451d50a37d6d97ac1abf09c1f15dd23411b818e" and "fa325072ac9f39b088ec4d7868acae66d8f86036" have entirely different histories.
3451d50a37
...
fa325072ac
@ -108,11 +108,6 @@ int command_match_builtins(command_t* cmd)
|
||||
printf("pid %ld, ppid %ld, uid %d (%s), gid %d\n", getpid(), getppid(), getuid(), username, getgid());
|
||||
return 1;
|
||||
}
|
||||
if (command_matches(cmd, "sleep"))
|
||||
{
|
||||
sleep(atoi(cmd->buffer + 6));
|
||||
return 1;
|
||||
}
|
||||
if (command_matches_exactly(cmd, "clear"))
|
||||
{
|
||||
fputs("\033@", stdout); // clear screen. for now, escape sequences in luna are non-standard.
|
||||
|
@ -1,61 +0,0 @@
|
||||
mkdir /tmp/folder0
|
||||
sleep 1
|
||||
mkdir /tmp/folder1
|
||||
sleep 1
|
||||
mkdir /tmp/folder2
|
||||
sleep 1
|
||||
mkdir /tmp/folder3
|
||||
sleep 1
|
||||
mkdir /tmp/folder4
|
||||
sleep 1
|
||||
mkdir /tmp/folder5
|
||||
sleep 1
|
||||
mkdir /tmp/folder6
|
||||
sleep 1
|
||||
mkdir /tmp/folder7
|
||||
sleep 1
|
||||
mkdir /tmp/folder8
|
||||
sleep 1
|
||||
mkdir /tmp/folder9
|
||||
sleep 1
|
||||
mkdir /tmp/folder10
|
||||
sleep 1
|
||||
mkdir /tmp/folder11
|
||||
sleep 1
|
||||
mkdir /tmp/folder12
|
||||
sleep 1
|
||||
mkdir /tmp/folder13
|
||||
sleep 1
|
||||
mkdir /tmp/folder14
|
||||
sleep 1
|
||||
mkdir /tmp/folder15
|
||||
sleep 1
|
||||
mkdir /tmp/folder16
|
||||
sleep 1
|
||||
mkdir /tmp/folder17
|
||||
sleep 1
|
||||
mkdir /tmp/folder18
|
||||
sleep 1
|
||||
mkdir /tmp/folder19
|
||||
sleep 1
|
||||
mkdir /tmp/folder20
|
||||
sleep 1
|
||||
mkdir /tmp/folder21
|
||||
sleep 1
|
||||
mkdir /tmp/folder22
|
||||
sleep 1
|
||||
mkdir /tmp/folder23
|
||||
sleep 1
|
||||
mkdir /tmp/folder24
|
||||
sleep 1
|
||||
mkdir /tmp/folder25
|
||||
sleep 1
|
||||
mkdir /tmp/folder26
|
||||
sleep 1
|
||||
mkdir /tmp/folder27
|
||||
sleep 1
|
||||
mkdir /tmp/folder28
|
||||
sleep 1
|
||||
mkdir /tmp/folder29
|
||||
sleep 1
|
||||
mkdir /tmp/folder30
|
@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "fs/VFS.h"
|
||||
|
||||
namespace TmpFS
|
||||
{
|
||||
VFS::Node* get();
|
||||
|
||||
VFS::Node* finddir(VFS::Node* node, const char* filename);
|
||||
VFS::Node* readdir(VFS::Node* node, long offset);
|
||||
|
||||
int mkdir(VFS::Node* node, const char* name, mode_t mode);
|
||||
|
||||
ssize_t read(VFS::Node* node, size_t offset, size_t length, char* buffer);
|
||||
ssize_t write(VFS::Node* node, size_t offset, size_t length, char* buffer);
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
#ifndef _MOON_CLOG_H
|
||||
#define _MOON_CLOG_H
|
||||
|
||||
enum log_level
|
||||
{
|
||||
LOG_DEBUG,
|
||||
LOG_INFO,
|
||||
LOG_WARN,
|
||||
LOG_ERROR
|
||||
};
|
||||
|
||||
#define PRINTF_LIKE(n, m) __attribute__((format(printf, n, m)))
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void clog_log(const char* function, enum log_level level, const char* message, ...) PRINTF_LIKE(3, 4);
|
||||
void clog_logln(const char* function, enum log_level level, const char* message, ...) PRINTF_LIKE(3, 4);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MODULE
|
||||
#define kcommonlog(function, level, ...) clog_##function(__FUNCTION__, level, __VA_ARGS__)
|
||||
#else
|
||||
#define kcommonlog(function, level, ...) clog_##function(MODULE, level, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define kdbg(...) kcommonlog(log, LOG_DEBUG, __VA_ARGS__)
|
||||
#define kdbgln(...) kcommonlog(logln, LOG_DEBUG, __VA_ARGS__)
|
||||
#define kinfo(...) kcommonlog(log, LOG_INFO, __VA_ARGS__)
|
||||
#define kinfoln(...) kcommonlog(logln, LOG_INFO, __VA_ARGS__)
|
||||
#define kwarn(...) kcommonlog(log, LOG_WARN, __VA_ARGS__)
|
||||
#define kwarnln(...) kcommonlog(logln, LOG_WARN, __VA_ARGS__)
|
||||
#define kerror(...) kcommonlog(log, LOG_ERROR, __VA_ARGS__)
|
||||
#define kerrorln(...) kcommonlog(logln, LOG_ERROR, __VA_ARGS__)
|
||||
|
||||
#endif
|
@ -1,167 +0,0 @@
|
||||
#pragma once
|
||||
#include "log/Log.h"
|
||||
#include "std/ensure.h"
|
||||
#include "std/stdlib.h"
|
||||
#include "std/string.h"
|
||||
#include "utils/new.h"
|
||||
|
||||
#define __noinline __attribute__((noinline))
|
||||
|
||||
template <typename T> struct Dynamic
|
||||
{
|
||||
Dynamic()
|
||||
{
|
||||
set_expand_rate(16);
|
||||
ensure(expand_fixed());
|
||||
}
|
||||
|
||||
Dynamic(size_t capacity)
|
||||
{
|
||||
set_expand_rate(16);
|
||||
ensure(expand_fixed());
|
||||
}
|
||||
|
||||
Dynamic(const Dynamic<T>& other)
|
||||
{
|
||||
set_expand_rate(other.m_expand_rate);
|
||||
ensure_capacity(other.capacity());
|
||||
m_size = other.size();
|
||||
memcpy(m_buf, other.data(), m_capacity * sizeof(T));
|
||||
}
|
||||
|
||||
Dynamic(Dynamic<T>&& other)
|
||||
{
|
||||
set_expand_rate(other.m_expand_rate);
|
||||
m_buf = other.release_data();
|
||||
m_capacity = other.capacity();
|
||||
m_size = other.size();
|
||||
}
|
||||
|
||||
Dynamic<T>& operator=(const Dynamic<T>& other)
|
||||
{
|
||||
if (this == &other) return *this;
|
||||
|
||||
if (m_buf)
|
||||
{
|
||||
while (m_size) pop(); // destroy all objects
|
||||
kfree(m_buf);
|
||||
}
|
||||
|
||||
set_expand_rate(other.m_expand_rate);
|
||||
ensure_capacity(other.capacity());
|
||||
m_size = other.size();
|
||||
memcpy(m_buf, other.data(), m_capacity * sizeof(T));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Dynamic()
|
||||
{
|
||||
if (m_buf)
|
||||
{
|
||||
while (m_size) pop(); // destroy all objects
|
||||
kfree(m_buf);
|
||||
}
|
||||
}
|
||||
|
||||
T& at(size_t index)
|
||||
{
|
||||
ensure(index < m_size);
|
||||
return m_buf[index];
|
||||
}
|
||||
|
||||
const T& at(size_t index) const
|
||||
{
|
||||
ensure(index < m_size);
|
||||
return m_buf[index];
|
||||
}
|
||||
|
||||
T& operator[](size_t index)
|
||||
{
|
||||
return at(index);
|
||||
}
|
||||
|
||||
const T& operator[](size_t index) const
|
||||
{
|
||||
return at(index);
|
||||
}
|
||||
|
||||
bool expand_capacity(size_t capacity)
|
||||
{
|
||||
return expand(capacity);
|
||||
}
|
||||
|
||||
void ensure_capacity(size_t capacity)
|
||||
{
|
||||
ensure(expand(capacity));
|
||||
}
|
||||
|
||||
void set_expand_rate(size_t rate)
|
||||
{
|
||||
if (!rate) return;
|
||||
m_expand_rate = rate;
|
||||
}
|
||||
|
||||
__noinline bool push(const T& item)
|
||||
{
|
||||
if (m_size == m_capacity)
|
||||
if (!expand_fixed()) return false;
|
||||
m_size++;
|
||||
T* loc = ptr_at(m_size - 1);
|
||||
new (loc) T(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
void pop()
|
||||
{
|
||||
at(m_size - 1).~T();
|
||||
m_size--;
|
||||
}
|
||||
|
||||
size_t capacity() const
|
||||
{
|
||||
return m_capacity;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
const T* data() const
|
||||
{
|
||||
return m_buf;
|
||||
}
|
||||
|
||||
T* release_data()
|
||||
{
|
||||
T* result = m_buf;
|
||||
m_buf = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
T* m_buf = nullptr;
|
||||
size_t m_capacity = 0;
|
||||
size_t m_size = 0;
|
||||
size_t m_expand_rate = 16;
|
||||
|
||||
bool expand(size_t new_capacity)
|
||||
{
|
||||
m_buf = (T*)krealloc(m_buf, new_capacity * sizeof(T));
|
||||
if (!m_buf) return false;
|
||||
m_capacity = new_capacity;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool expand_fixed()
|
||||
{
|
||||
ensure(m_expand_rate != 0);
|
||||
return expand(m_capacity + m_expand_rate);
|
||||
}
|
||||
|
||||
T* ptr_at(size_t index)
|
||||
{
|
||||
return (T*)((char*)m_buf + index * sizeof(T));
|
||||
}
|
||||
};
|
@ -226,7 +226,6 @@ int initrd_mkdir(VFS::Node* node, const char* name, mode_t mode) // FIXME: Retur
|
||||
new_node.inode = inode;
|
||||
new_node.find_func = initrd_scan_dir;
|
||||
new_node.mkdir_func = initrd_mkdir;
|
||||
new_node.readdir_func = initrd_read_dir;
|
||||
new_node.length = 0;
|
||||
new_node.type = VFS_DIRECTORY;
|
||||
new_node.mode = mode;
|
||||
|
@ -1,94 +0,0 @@
|
||||
#include "fs/TmpFS.h"
|
||||
#include "std/errno.h"
|
||||
#include "std/string.h"
|
||||
#include "utils/Dynamic.h"
|
||||
#include "utils/move.h"
|
||||
|
||||
namespace TmpFS
|
||||
{
|
||||
struct File
|
||||
{
|
||||
char* ptr;
|
||||
uint64_t pages;
|
||||
uint64_t length;
|
||||
};
|
||||
|
||||
struct Directory
|
||||
{
|
||||
Dynamic<VFS::Node*> files;
|
||||
};
|
||||
}
|
||||
|
||||
VFS::Node* tmpfs_root = nullptr;
|
||||
|
||||
Dynamic<TmpFS::Directory> tmpfs_dirs;
|
||||
Dynamic<TmpFS::File> tmpfs_files;
|
||||
|
||||
extern uint64_t clock_now();
|
||||
|
||||
VFS::Node* TmpFS::get()
|
||||
{
|
||||
if (tmpfs_root) return tmpfs_root;
|
||||
tmpfs_root = new VFS::Node;
|
||||
tmpfs_root->length = 0;
|
||||
tmpfs_root->inode = 0;
|
||||
tmpfs_root->type = VFS_DIRECTORY;
|
||||
tmpfs_root->find_func = TmpFS::finddir;
|
||||
tmpfs_root->readdir_func = TmpFS::readdir;
|
||||
tmpfs_root->mkdir_func = TmpFS::mkdir;
|
||||
tmpfs_root->mode = 0755;
|
||||
tmpfs_root->uid = tmpfs_root->gid = 0;
|
||||
tmpfs_root->atime = tmpfs_root->ctime = tmpfs_root->mtime = clock_now();
|
||||
strncpy(tmpfs_root->name, "tmpfs", sizeof(tmpfs_root->name));
|
||||
tmpfs_dirs.ensure_capacity(16);
|
||||
tmpfs_files.ensure_capacity(16);
|
||||
tmpfs_dirs.set_expand_rate(16);
|
||||
tmpfs_files.set_expand_rate(16);
|
||||
ensure(tmpfs_dirs.push({{}}));
|
||||
return tmpfs_root;
|
||||
}
|
||||
|
||||
VFS::Node* TmpFS::finddir(VFS::Node* node, const char* filename)
|
||||
{
|
||||
if (!node) return nullptr;
|
||||
if (node->inode >= tmpfs_dirs.size()) return nullptr;
|
||||
auto& dir = tmpfs_dirs[node->inode];
|
||||
for (size_t i = 0; i < dir.files.size(); i++)
|
||||
{
|
||||
if (!strncmp(dir.files[i]->name, filename, sizeof(dir.files[i]->name))) return dir.files[i];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VFS::Node* TmpFS::readdir(VFS::Node* node, long offset)
|
||||
{
|
||||
if (!node) return nullptr;
|
||||
if (node->inode >= tmpfs_dirs.size()) return nullptr;
|
||||
auto& dir = tmpfs_dirs[node->inode];
|
||||
if (offset < 0) return nullptr;
|
||||
if ((size_t)offset >= dir.files.size()) return nullptr;
|
||||
return dir.files[offset];
|
||||
}
|
||||
|
||||
int TmpFS::mkdir(VFS::Node* node, const char* name, mode_t mode)
|
||||
{
|
||||
if (node->inode >= tmpfs_dirs.size()) return -EINVAL;
|
||||
if (!(node->type & VFS_DIRECTORY)) return -ENOTDIR;
|
||||
auto& parent = tmpfs_dirs[node->inode];
|
||||
uint64_t inode = tmpfs_dirs.size();
|
||||
VFS::Node* new_node = new VFS::Node;
|
||||
new_node->inode = inode;
|
||||
new_node->find_func = TmpFS::finddir;
|
||||
new_node->readdir_func = TmpFS::readdir;
|
||||
new_node->mkdir_func = TmpFS::mkdir;
|
||||
new_node->length = 0;
|
||||
new_node->type = VFS_DIRECTORY;
|
||||
new_node->mode = mode;
|
||||
new_node->uid = new_node->gid = 0;
|
||||
new_node->atime = new_node->ctime = new_node->mtime = clock_now();
|
||||
strncpy(new_node->name, name, sizeof(new_node->name));
|
||||
ensure(tmpfs_dirs.push({{}}));
|
||||
node->length++;
|
||||
ensure(parent.files.push(new_node));
|
||||
return 0;
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
#include "log/CLog.h"
|
||||
#include "std/stdio.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
enum class LogLevel
|
||||
{
|
||||
DEBUG,
|
||||
INFO,
|
||||
WARN,
|
||||
ERROR
|
||||
};
|
||||
|
||||
enum class Backend
|
||||
{
|
||||
Serial,
|
||||
Console
|
||||
};
|
||||
|
||||
namespace KernelLog
|
||||
{
|
||||
void log(const char* function, LogLevel level, const char* message, ...) PRINTF_LIKE(3, 4);
|
||||
void logln(const char* function, LogLevel level, const char* message, ...) PRINTF_LIKE(3, 4);
|
||||
}
|
||||
|
||||
void log_backend_serial(const char* function, LogLevel level, const char* message, va_list origin);
|
||||
void log_backend_console(const char* function, LogLevel level, const char* message, va_list origin);
|
||||
bool log_level_enabled(LogLevel level);
|
||||
bool log_backend_enabled(Backend backend);
|
||||
|
||||
extern "C" void clog_log(const char* function, enum log_level level, const char* message, ...)
|
||||
{
|
||||
if (!log_level_enabled((LogLevel)level)) return;
|
||||
va_list ap;
|
||||
va_start(ap, message);
|
||||
if (log_backend_enabled(Backend::Serial)) log_backend_serial(function, (LogLevel)level, message, ap);
|
||||
if (log_backend_enabled(Backend::Console)) log_backend_console(function, (LogLevel)level, message, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
extern "C" void clog_logln(const char* function, enum log_level level, const char* message, ...)
|
||||
{
|
||||
if (!log_level_enabled((LogLevel)level)) return;
|
||||
va_list ap;
|
||||
va_start(ap, message);
|
||||
if (log_backend_enabled(Backend::Serial))
|
||||
{
|
||||
log_backend_serial(function, (LogLevel)level, message, ap);
|
||||
printf("\n");
|
||||
}
|
||||
if (log_backend_enabled(Backend::Console))
|
||||
{
|
||||
log_backend_console(function, (LogLevel)level, message, ap);
|
||||
kprintf("\n");
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
@ -8,17 +8,17 @@
|
||||
static int level_mask = 15;
|
||||
static int backend_mask = 3;
|
||||
|
||||
bool log_level_enabled(LogLevel level)
|
||||
static bool log_level_enabled(LogLevel level)
|
||||
{
|
||||
return level_mask & (1 << (int)level);
|
||||
}
|
||||
|
||||
bool log_backend_enabled(Backend backend)
|
||||
static bool log_backend_enabled(Backend backend)
|
||||
{
|
||||
return backend_mask & (1 << (int)backend);
|
||||
}
|
||||
|
||||
void log_backend_serial(const char* function, LogLevel level, const char* message, va_list origin)
|
||||
static void log_backend_serial(const char* function, LogLevel level, const char* message, va_list origin)
|
||||
{
|
||||
va_list ap;
|
||||
va_copy(ap, origin);
|
||||
@ -41,7 +41,8 @@ void log_backend_serial(const char* function, LogLevel level, const char* messag
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void log_backend_console(const char* function, [[maybe_unused]] LogLevel level, const char* message, va_list origin)
|
||||
static void log_backend_console(const char* function, [[maybe_unused]] LogLevel level, const char* message,
|
||||
va_list origin)
|
||||
{
|
||||
va_list ap;
|
||||
va_copy(ap, origin);
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "cpu/CPU.h"
|
||||
#include "fs/TmpFS.h"
|
||||
#include "fs/devices/DeviceFS.h"
|
||||
#include "gdt/GDT.h"
|
||||
#include "init/Init.h"
|
||||
@ -59,9 +58,7 @@ extern "C" void _start()
|
||||
});
|
||||
|
||||
ensure(VFS::mkdir("/dev") == 0);
|
||||
ensure(VFS::mkdir("/tmp") == 0);
|
||||
VFS::mount("/dev", DeviceFS::get());
|
||||
VFS::mount("/tmp", TmpFS::get());
|
||||
|
||||
Init::finish_kernel_boot();
|
||||
|
||||
|
@ -1,7 +1,4 @@
|
||||
#define MODULE "alloc"
|
||||
|
||||
#include "memory/liballoc/liballoc.h"
|
||||
#include "log/CLog.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -552,7 +549,10 @@ void PREFIX(free)(void* ptr)
|
||||
if (ptr == NULL)
|
||||
{
|
||||
l_warningCount += 1;
|
||||
kwarnln("kfree( NULL ) called from %p", __builtin_return_address(0));
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: WARNING: PREFIX(free)( NULL ) called from %x\n", __builtin_return_address(0));
|
||||
FLUSH();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@ -571,14 +571,27 @@ void PREFIX(free)(void* ptr)
|
||||
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) || ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF)))
|
||||
{
|
||||
l_possibleOverruns += 1;
|
||||
kerrorln("Possible 1-3 byte overrun for magic %x != %x", min->magic, LIBALLOC_MAGIC);
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n", min->magic, LIBALLOC_MAGIC);
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (min->magic == LIBALLOC_DEAD)
|
||||
{
|
||||
kerrorln("double free attempt on %p from %p.", ptr, __builtin_return_address(0));
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n", ptr,
|
||||
__builtin_return_address(0));
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n", ptr, __builtin_return_address(0));
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
else { kerrorln("Bad kfree(%p) called from %p\n", ptr, __builtin_return_address(0)); }
|
||||
|
||||
// being lied to...
|
||||
liballoc_unlock(); // release the lock
|
||||
@ -683,14 +696,27 @@ void* PREFIX(realloc)(void* p, size_t size)
|
||||
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) || ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF)))
|
||||
{
|
||||
l_possibleOverruns += 1;
|
||||
kerrorln("Possible 1-3 byte overrun for magic %x != %x", min->magic, LIBALLOC_MAGIC);
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n", min->magic, LIBALLOC_MAGIC);
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (min->magic == LIBALLOC_DEAD)
|
||||
{
|
||||
kerrorln("realloc after free attempt on %p from %p.", ptr, __builtin_return_address(0));
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n", ptr,
|
||||
__builtin_return_address(0));
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n", ptr, __builtin_return_address(0));
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
else { kerrorln("Bad krealloc(%p) called from %p\n", ptr, __builtin_return_address(0)); }
|
||||
|
||||
// being lied to...
|
||||
liballoc_unlock(); // release the lock
|
||||
|
@ -40,7 +40,6 @@ template <typename Callback> void sched_for_each_task(Callback callback)
|
||||
Task* task = base_task;
|
||||
if (!task) return;
|
||||
do {
|
||||
if (!task) break;
|
||||
bool will_continue = callback(task);
|
||||
if (!will_continue) break;
|
||||
task = task->next_task;
|
||||
|
Loading…
Reference in New Issue
Block a user