使用Rust重构CFS调度器 (#131)

* 新建调度器的文件

* 把softirq vector移动到c文件中(原来在.h)

* 将进程切换方式改为“中断返回时切换”

* new:使用rust重构CFS

* 删除已经在smp中废弃的HPET中断转发函数

* 代码格式化

* 删除多余的dunce依赖
This commit is contained in:
login 2022-12-31 17:26:12 +08:00 committed by GitHub
parent 156949680c
commit d4f3de93a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 464 additions and 1027 deletions

View File

@ -36,6 +36,7 @@ export CC=$(DragonOS_GCC)/x86_64-elf-gcc
export LD=ld
export AS=$(DragonOS_GCC)/x86_64-elf-as
export NM=$(DragonOS_GCC)/x86_64-elf-nm
export AR=$(DragonOS_GCC)/x86_64-elf-ar
export OBJCOPY=$(DragonOS_GCC)/x86_64-elf-objcopy

View File

@ -15,5 +15,5 @@ x86_64 = "0.14.10"
# 构建时依赖项
[build-dependencies]
bindgen = "0.61.0"
cbindgen = "0.24.3"

View File

@ -1,7 +1,4 @@
extern crate bindgen;
extern crate cbindgen;
// use ::std::env;
use std::path::PathBuf;
@ -21,7 +18,7 @@ fn main() {
let bindings = bindgen::Builder::default()
.clang_arg("-I./src")
.clang_arg("-I./src/include")
.clang_arg("-I./src/arch/x86_64/include") // todo: 当引入多种架构之后需要修改这里对于不同的架构编译时include不同的路径
.clang_arg("-I./src/arch/x86_64/include") // todo: 当引入多种架构之后需要修改这里对于不同的架构编译时include不同的路径
// The input header we would like to generate
// bindings for.
.header("src/include/bindings/wrapper.h")

View File

@ -1,626 +0,0 @@
# The language to output bindings in
#
# possible values: "C", "C++", "Cython"
#
# default: "C++"
language = "C"
# Options for wrapping the contents of the header:
# 在文件头部添加的注释信息
# An optional string of text to output at the beginning of the generated file
# default: doesn't emit anything
header = "/* DragonOS's C FFI for rust. This file is licensed under GPLv2 */"
# 在文件尾部添加的信息
# An optional string of text to output at the end of the generated file
# default: doesn't emit anything
# trailer = "/* Text to put at the end of the generated file */"
# An optional name to use as an include guard
# default: doesn't emit an include guard
# include_guard = "mozilla_wr_bindings_h"
# 是否生成一个 `#pragma once`
pragma_once = true
# An optional string of text to output between major sections of the generated
# file as a warning against manual editing
#
# default: doesn't emit anything
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
# Whether to include a comment with the version of cbindgen used to generate the file
# default: false
# include_version = true
# An optional namespace to output around the generated bindings
# default: doesn't emit a namespace
namespace = "ffi"
# An optional list of namespaces to output around the generated bindings
# default: []
# namespaces = ["mozilla", "wr"]
# An optional list of namespaces to declare as using with "using namespace"
# default: []
# using_namespaces = ["mozilla", "wr"]
# A list of sys headers to #include (with angle brackets)
# default: []
sys_includes = ["stdint.h"]
# 生成的binding文件要include的头文件
# A list of headers to #include (with quotes)
# default: []
includes = []
# Whether cbindgen's default C/C++ standard imports should be suppressed. These
# imports are included by default because our generated headers tend to require
# them (e.g. for uint32_t). Currently, the generated imports are:
#
# * for C: <stdarg.h>, <stdbool.h>, <stdint.h>, <stdlib.h>, <uchar.h>
#
# * for C++: <cstdarg>, <cstdint>, <cstdlib>, <new>, <cassert> (depending on config)
#
# default: false
no_includes = true
# Whether to make a C header C++ compatible.
# These will wrap generated functions into a `extern "C"` block, e.g.
#
# #ifdef __cplusplus
# extern "C" {
# #endif // __cplusplus
#
# // Generated functions.
#
# #ifdef __cplusplus
# } // extern "C"
# #endif // __cplusplus
#
# If the language is not C this option won't have any effect.
#
# default: false
cpp_compat = false
# A list of lines to add verbatim after the includes block
#after_includes = "#define VERSION 1"
# Code Style Options
# The style to use for curly braces
#
# possible values: "SameLine", "NextLine"
#
# default: "SameLine"
braces = "NextLine"
# The desired length of a line to use when formatting lines
# default: 100
line_length = 120
# The amount of spaces to indent by
# default: 2
tab_width = 4
# Include doc comments from Rust as documentation
documentation = true
# How the generated documentation should be commented.
#
# possible values:
# * "c": /* like this */
# * "c99": // like this
# * "c++": /// like this
# * "doxy": like C, but with leading *'s on each line
# * "auto": "c++" if that's the language, "doxy" otherwise
#
# default: "auto"
documentation_style = "doxy"
# How much of the documentation for each item is output.
#
# possible values:
# * "short": Only the first line.
# * "full": The full documentation.
#
# default: "full"
documentation_length = "short"
# Codegen Options
# When generating a C header, the kind of declaration style to use for structs
# or enums.
#
# possible values:
# * "type": typedef struct { ... } MyType;
# * "tag": struct MyType { ... };
# * "both": typedef struct MyType { ... } MyType;
#
# default: "both"
style = "both"
# If this option is true `usize` and `isize` will be converted into `size_t` and `ptrdiff_t`
# instead of `uintptr_t` and `intptr_t` respectively.
usize_is_size_t = true
# A list of substitutions for converting cfg's to ifdefs. cfgs which aren't
# defined here will just be discarded.
#
# e.g.
# `#[cfg(target = "freebsd")] ...`
# becomes
# `#if defined(DEFINE_FREEBSD) ... #endif`
[defines]
"target_os = freebsd" = "DEFINE_FREEBSD"
"feature = serde" = "DEFINE_SERDE"
[export]
# A list of additional items to always include in the generated bindings if they're
# found but otherwise don't appear to be used by the public API.
#
# default: []
include = ["MyOrphanStruct", "MyGreatTypeRename"]
# A list of items to not include in the generated bindings
# default: []
exclude = ["Bad"]
# 生成的内容的前缀
# A prefix to add before the name of every item
# default: no prefix is added
# prefix = "CAPI_"
# Types of items that we'll generate. If empty, then all types of item are emitted.
#
# possible items: (TODO: explain these in detail)
# * "constants":
# * "globals":
# * "enums":
# * "structs":
# * "unions":
# * "typedefs":
# * "opaque":
# * "functions":
#
# default: []
item_types = ["enums", "structs", "opaque", "functions"]
# Whether applying rules in export.rename prevents export.prefix from applying.
#
# e.g. given this toml:
#
# [export]
# prefix = "capi_"
# [export.rename]
# "MyType" = "my_cool_type"
#
# You get the following results:
#
# renaming_overrides_prefixing = true:
# "MyType" => "my_cool_type"
#
# renaming_overrides_prefixing = false:
# "MyType => capi_my_cool_type"
#
# default: false
renaming_overrides_prefixing = true
# Table of name conversions to apply to item names (lhs becomes rhs)
[export.rename]
"MyType" = "my_cool_type"
"my_function" = "BetterFunctionName"
# Table of things to prepend to the body of any struct, union, or enum that has the
# given name. This can be used to add things like methods which don't change ABI,
# mark fields private, etc
[export.pre_body]
"MyType" = """
MyType() = delete;
private:
"""
# Table of things to append to the body of any struct, union, or enum that has the
# given name. This can be used to add things like methods which don't change ABI.
[export.body]
"MyType" = """
void cppMethod() const;
"""
# Configuration for name mangling
[export.mangle]
# Whether the types should be renamed during mangling, for example
# c_char -> CChar, etc.
rename_types = "PascalCase"
# Whether the underscores from the mangled name should be omitted.
remove_underscores = false
[layout]
# A string that should come before the name of any type which has been marked
# as `#[repr(packed)]`. For instance, "__attribute__((packed))" would be a
# reasonable value if targeting gcc/clang. A more portable solution would
# involve emitting the name of a macro which you define in a platform-specific
# way. e.g. "PACKED"
#
# default: `#[repr(packed)]` types will be treated as opaque, since it would
# be unsafe for C callers to use a incorrectly laid-out union.
packed = "PACKED"
# A string that should come before the name of any type which has been marked
# as `#[repr(align(n))]`. This string must be a function-like macro which takes
# a single argument (the requested alignment, `n`). For instance, a macro
# `#define`d as `ALIGNED(n)` in `header` which translates to
# `__attribute__((aligned(n)))` would be a reasonable value if targeting
# gcc/clang.
#
# default: `#[repr(align(n))]` types will be treated as opaque, since it
# could be unsafe for C callers to use a incorrectly-aligned union.
aligned_n = "ALIGNED"
[fn]
# 函数开头要加入的内容
# An optional prefix to put before every function declaration
# default: no prefix added
# prefix = "WR_START_FUNC"
# 函数声明的结尾要加入的内容
# An optional postfix to put after any function declaration
# default: no postix added
# postfix = "WR_END_FUNC"
# How to format function arguments
#
# possible values:
# * "horizontal": place all arguments on the same line
# * "vertical": place each argument on its own line
# * "auto": only use vertical if horizontal would exceed line_length
#
# default: "auto"
args = "horizontal"
# An optional string that should prefix function declarations which have been
# marked as `#[must_use]`. For instance, "__attribute__((warn_unused_result))"
# would be a reasonable value if targeting gcc/clang. A more portable solution
# would involve emitting the name of a macro which you define in a
# platform-specific way. e.g. "MUST_USE_FUNC"
# default: nothing is emitted for must_use functions
must_use = "MUST_USE_FUNC"
# An optional string that will be used in the attribute position for functions
# that don't return (that return `!` in Rust).
#
# For instance, `__attribute__((noreturn))` would be a reasonable value if
# targeting gcc/clang.
no_return = "NO_RETURN"
# An optional string that, if present, will be used to generate Swift function
# and method signatures for generated functions, for example "CF_SWIFT_NAME".
# If no such macro is available in your toolchain, you can define one using the
# `header` option in cbindgen.toml
# default: no swift_name function attributes are generated
# swift_name_macro = "CF_SWIFT_NAME"
# A rule to use to rename function argument names. The renaming assumes the input
# is the Rust standard snake_case, however it accepts all the different rename_args
# inputs. This means many options here are no-ops or redundant.
#
# possible values (that actually do something):
# * "CamelCase": my_arg => myArg
# * "PascalCase": my_arg => MyArg
# * "GeckoCase": my_arg => aMyArg
# * "ScreamingSnakeCase": my_arg => MY_ARG
# * "None": apply no renaming
#
# technically possible values (that shouldn't have a purpose here):
# * "SnakeCase": apply no renaming
# * "LowerCase": apply no renaming (actually applies to_lowercase, is this bug?)
# * "UpperCase": same as ScreamingSnakeCase in this context
# * "QualifiedScreamingSnakeCase" => same as ScreamingSnakeCase in this context
#
# default: "None"
rename_args = "PascalCase"
# This rule specifies the order in which functions will be sorted.
#
# "Name": sort by the name of the function
# "None": keep order in which the functions have been parsed
#
# default: "None"
sort_by = "Name"
[struct]
# A rule to use to rename struct field names. The renaming assumes the input is
# the Rust standard snake_case, however it acccepts all the different rename_args
# inputs. This means many options here are no-ops or redundant.
#
# possible values (that actually do something):
# * "CamelCase": my_arg => myArg
# * "PascalCase": my_arg => MyArg
# * "GeckoCase": my_arg => mMyArg
# * "ScreamingSnakeCase": my_arg => MY_ARG
# * "None": apply no renaming
#
# technically possible values (that shouldn't have a purpose here):
# * "SnakeCase": apply no renaming
# * "LowerCase": apply no renaming (actually applies to_lowercase, is this bug?)
# * "UpperCase": same as ScreamingSnakeCase in this context
# * "QualifiedScreamingSnakeCase" => same as ScreamingSnakeCase in this context
#
# default: "None"
rename_fields = "PascalCase"
# An optional string that should come before the name of any struct which has been
# marked as `#[must_use]`. For instance, "__attribute__((warn_unused))"
# would be a reasonable value if targeting gcc/clang. A more portable solution
# would involve emitting the name of a macro which you define in a
# platform-specific way. e.g. "MUST_USE_STRUCT"
#
# default: nothing is emitted for must_use structs
must_use = "MUST_USE_STRUCT"
# Whether a Rust type with associated consts should emit those consts inside the
# type's body. Otherwise they will be emitted trailing and with the type's name
# prefixed. This does nothing if the target is C, or if
# [const]allow_static_const = false
#
# default: false
# associated_constants_in_body: false
# Whether to derive a simple constructor that takes a value for every field.
# default: false
derive_constructor = true
# Whether to derive an operator== for all structs
# default: false
derive_eq = false
# Whether to derive an operator!= for all structs
# default: false
derive_neq = false
# Whether to derive an operator< for all structs
# default: false
derive_lt = false
# Whether to derive an operator<= for all structs
# default: false
derive_lte = false
# Whether to derive an operator> for all structs
# default: false
derive_gt = false
# Whether to derive an operator>= for all structs
# default: false
derive_gte = false
[enum]
# A rule to use to rename enum variants, and the names of any fields those
# variants have. This should probably be split up into two separate options, but
# for now, they're the same! See the documentation for `[struct]rename_fields`
# for how this applies to fields. Renaming of the variant assumes that the input
# is the Rust standard PascalCase. In the case of QualifiedScreamingSnakeCase,
# it also assumed that the enum's name is PascalCase.
#
# possible values (that actually do something):
# * "CamelCase": MyVariant => myVariant
# * "SnakeCase": MyVariant => my_variant
# * "ScreamingSnakeCase": MyVariant => MY_VARIANT
# * "QualifiedScreamingSnakeCase": MyVariant => ENUM_NAME_MY_VARIANT
# * "LowerCase": MyVariant => myvariant
# * "UpperCase": MyVariant => MYVARIANT
# * "None": apply no renaming
#
# technically possible values (that shouldn't have a purpose for the variants):
# * "PascalCase": apply no renaming
# * "GeckoCase": apply no renaming
#
# default: "None"
rename_variants = "None"
# Whether an extra "sentinel" enum variant should be added to all generated enums.
# Firefox uses this for their IPC serialization library.
#
# WARNING: if the sentinel is ever passed into Rust, behaviour will be Undefined.
# Rust does not know about this value, and will assume it cannot happen.
#
# default: false
add_sentinel = false
# Whether enum variant names should be prefixed with the name of the enum.
# default: false
prefix_with_name = false
# Whether to emit enums using "enum class" when targeting C++.
# default: true
enum_class = true
# Whether to generate static `::MyVariant(..)` constructors and `bool IsMyVariant()`
# methods for enums with fields.
#
# default: false
derive_helper_methods = false
# Whether to generate `const MyVariant& AsMyVariant() const` methods for enums with fields.
# default: false
derive_const_casts = false
# Whether to generate `MyVariant& AsMyVariant()` methods for enums with fields
# default: false
derive_mut_casts = false
# The name of the macro/function to use for asserting `IsMyVariant()` in the body of
# derived `AsMyVariant()` cast methods.
#
# default: "assert" (but also causes `<cassert>` to be included by default)
cast_assert_name = "MOZ_RELEASE_ASSERT"
# An optional string that should come before the name of any enum which has been
# marked as `#[must_use]`. For instance, "__attribute__((warn_unused))"
# would be a reasonable value if targeting gcc/clang. A more portable solution
# would involve emitting the name of a macro which you define in a
# platform-specific way. e.g. "MUST_USE_ENUM"
#
# Note that this refers to the *output* type. That means this will not apply to an enum
# with fields, as it will be emitted as a struct. `[struct]must_use` will apply there.
#
# default: nothing is emitted for must_use enums
must_use = "MUST_USE_ENUM"
# Whether enums with fields should generate destructors. This exists so that generic
# enums can be properly instantiated with payloads that are C++ types with
# destructors. This isn't necessary for structs because C++ has rules to
# automatically derive the correct constructors and destructors for those types.
#
# Care should be taken with this option, as Rust and C++ cannot
# properly interoperate with eachother's notions of destructors. Also, this may
# change the ABI for the type. Either your destructor-full enums must live
# exclusively within C++, or they must only be passed by-reference between
# C++ and Rust.
#
# default: false
derive_tagged_enum_destructor = false
# Whether enums with fields should generate copy-constructor. See the discussion on
# derive_tagged_enum_destructor for why this is both useful and very dangerous.
#
# default: false
derive_tagged_enum_copy_constructor = false
# Whether enums with fields should generate copy-assignment operators.
#
# This depends on also deriving copy-constructors, and it is highly encouraged
# for this to be set to true.
#
# default: false
derive_tagged_enum_copy_assignment = false
# Whether enums with fields should generate an empty, private destructor.
# This allows the auto-generated constructor functions to compile, if there are
# non-trivially constructible members. This falls in the same family of
# dangerousness as `derive_tagged_enum_copy_constructor` and co.
#
# default: false
private_default_tagged_enum_constructor = false
[const]
# Whether a generated constant can be a static const in C++ mode. I have no
# idea why you would turn this off.
#
# default: true
allow_static_const = true
# Whether a generated constant can be constexpr in C++ mode.
#
# default: true
allow_constexpr = false
# This rule specifies the order in which constants will be sorted.
#
# "Name": sort by the name of the constant
# "None": keep order in which the constants have been parsed
#
# default: "None"
sort_by = "Name"
[macro_expansion]
# Whether bindings should be generated for instances of the bitflags! macro.
# default: false
bitflags = true
# Options for how your Rust library should be parsed
[parse]
# Whether to parse dependent crates and include their types in the output
# default: false
parse_deps = true
# A white list of crate names that are allowed to be parsed. If this is defined,
# only crates found in this list will ever be parsed.
#
# default: there is no whitelist (NOTE: this is the opposite of [])
include = ["webrender", "webrender_traits"]
# A black list of crate names that are not allowed to be parsed.
# default: []
exclude = ["libc"]
# Whether to use a new temporary target directory when running `rustc -Zunpretty=expanded`.
# This may be required for some build processes.
#
# default: false
clean = false
# Which crates other than the top-level binding crate we should generate
# bindings for.
#
# default: []
# extra_bindings = ["my_awesome_dep"]
[parse.expand]
# A list of crate names that should be run through `cargo expand` before
# parsing to expand any macros. Note that if a crate is named here, it
# will always be parsed, even if the blacklist/whitelist says it shouldn't be.
#
# default: []
crates = ["euclid"]
# If enabled, use the `--all-features` option when expanding. Ignored when
# `features` is set. For backwards-compatibility, this is forced on if
# `expand = ["euclid"]` shorthand is used.
#
# default: false
all_features = false
# When `all_features` is disabled and this is also disabled, use the
# `--no-default-features` option when expanding.
#
# default: true
default_features = true
# A list of feature names that should be used when running `cargo expand`. This
# combines with `default_features` like in your `Cargo.toml`. Note that the features
# listed here are features for the current crate being built, *not* the crates
# being expanded. The crate's `Cargo.toml` must take care of enabling the
# appropriate features in its dependencies
#
# default: []
# features = ["cbindgen"]
[ptr]
# An optional string to decorate all pointers that are
# required to be non null. Nullability is inferred from the Rust type: `&T`,
# `&mut T` and `NonNull<T>` all require a valid pointer value.
non_null_attribute = "_Nonnull"
# Options specific to Cython bindings.

View File

@ -18,5 +18,6 @@ $(kernel_arch_x86_64_subdirs): ECHO
all: $(kernel_arch_x86_64_objs) $(kernel_arch_x86_64_subdirs)
clean:
echo "Done."

View File

@ -0,0 +1,19 @@
use crate::include::bindings::bindings::{process_control_block, switch_proc};
use core::sync::atomic::compiler_fence;
/// @brief 切换进程的上下文(没有切换页表的动作)
///
/// @param next 下一个进程的pcb
/// @param trap_frame 中断上下文的栈帧
#[inline(always)]
pub fn switch_process(
prev: &'static mut process_control_block,
next: &'static mut process_control_block,
) {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
unsafe {
switch_proc(prev, next);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}

View File

@ -0,0 +1,23 @@
#![allow(dead_code)]
use core::arch::asm;
#[inline(always)]
pub fn mfence(){
unsafe{
asm!("mfence");
}
}
#[inline(always)]
pub fn lfence(){
unsafe{
asm!("lfence");
}
}
#[inline(always)]
pub fn sfence(){
unsafe{
asm!("sfence");
}
}

View File

@ -0,0 +1,28 @@
pub mod barrier;
use crate::include::bindings::bindings::process_control_block;
use core::arch::asm;
use core::ptr::read_volatile;
use self::barrier::mfence;
/// @brief 切换进程的页表
///
/// @param 下一个进程的pcb。将会把它的页表切换进来。
///
/// @return 下一个进程的pcb(把它return的目的主要是为了归还所有权)
#[inline(always)]
#[allow(dead_code)]
pub fn switch_mm(
next_pcb: &'static mut process_control_block,
) -> &'static mut process_control_block {
mfence();
// kdebug!("to get pml4t");
let pml4t = unsafe { read_volatile(&next_pcb.mm.as_ref().unwrap().pgd) };
unsafe {
asm!("mov cr3, {}", in(reg) pml4t);
}
mfence();
return next_pcb;
}

View File

@ -1,4 +1,7 @@
#[macro_use]
pub mod asm;
pub mod cpu;
pub mod interrupt;
pub mod interrupt;
pub mod mm;
pub mod context;
pub mod sched;

View File

@ -0,0 +1,10 @@
use crate::include::bindings::bindings::{enter_syscall_int, SYS_SCHED};
/// @brief 若内核代码不处在中断上下文中那么将可以使用本函数发起一个sys_sched系统调用然后运行调度器。
/// 由于只能在中断上下文中进行进程切换因此需要发起一个系统调用SYS_SCHED。
#[no_mangle]
pub extern "C" fn sched() {
unsafe {
enter_syscall_int(SYS_SCHED.into(), 0, 0, 0, 0, 0, 0, 0, 0);
}
}

View File

@ -403,7 +403,7 @@ static bool ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t
port->ci = 1 << slot; // Issue command
current_pcb->flags |= PF_NEED_SCHED;
sched();
int retval = AHCI_SUCCESS;
// Wait for completion
while (1)
@ -483,7 +483,6 @@ static bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_
port->ci = 1; // Issue command
current_pcb->flags |= PF_NEED_SCHED;
sched();
int retval = AHCI_SUCCESS;
while (1)

View File

@ -1,4 +1,5 @@
#include "apic.h"
#include "apic_timer.h"
#include <common/kprint.h>
#include <common/printk.h>
#include <common/cpu.h>
@ -458,7 +459,7 @@ void do_IRQ(struct pt_regs *rsp, ul number)
kBUG("current_pcb->preempt_count<0! pid=%d", current_pcb->pid); // should not be here
// 检测当前进程是否可被调度
if (current_pcb->flags & PF_NEED_SCHED)
if (current_pcb->flags & PF_NEED_SCHED && number == APIC_TIMER_IRQ_NUM)
{
io_mfence();
sched();

View File

@ -70,7 +70,8 @@ int video_refresh_daemon(void *unused)
}
video_refresh_expire_jiffies = cal_next_n_ms_jiffies(REFRESH_INTERVAL << 1);
}
video_daemon_pcb->flags &= ~PROC_RUNNING;
video_daemon_pcb->state &= ~PROC_RUNNING;
video_daemon_pcb->flags |= PF_NEED_SCHED;
sched();
}

View File

@ -21,6 +21,7 @@ ES = 0x78
RAX = 0x80
FUNC = 0x88
ERRCODE = 0x90
//
RIP = 0x98
CS = 0xa0
RFLAGS = 0xa8
@ -111,51 +112,11 @@ Err_Code:
callq *%rdx // *
jmp ret_from_exception
//
//
ENTRY(system_call)
// sysenter
subq $0x38, %rsp
cld;
pushq %rax
movq %es, %rax
pushq %rax
movq %ds, %rax
pushq %rax
pushq %rbp
pushq %rdi
pushq %rsi
pushq %rdx
pushq %rcx
pushq %rbx
pushq %r8
pushq %r9
pushq %r10
pushq %r11
pushq %r12
pushq %r13
pushq %r14
pushq %r15
movq $0x10, %rdx
movq %rdx, %ds
movq %rdx, %es
// rspsystem_call_function
movq %rsp, %rdi
callq system_call_function
//
ENTRY(ret_from_system_call)
jmp Restore_all
// 0 #DE
ENTRY(divide_error)
@ -323,7 +284,7 @@ ENTRY(virtualization_exception)
//
// 0x80
ENTRY(syscall_int)
pushq $0

View File

@ -4,6 +4,7 @@
#include <driver/video/video.h>
#include <common/spinlock.h>
static struct softirq_t softirq_vector[MAX_SOFTIRQ_NUM] = {0};
static spinlock_t softirq_modify_lock; // 软中断状态status
static volatile uint64_t softirq_pending = 0;
static volatile uint64_t softirq_running = 0;

View File

@ -21,23 +21,18 @@
* @brief
*
*/
#define raise_softirq(sirq_num) \
do \
{ \
set_softirq_pending(1 << sirq_num); \
#define raise_softirq(sirq_num) \
do \
{ \
set_softirq_pending(1 << sirq_num); \
} while (0);
struct softirq_t
{
void (*action)(void *data); // 软中断处理函数
void *data;
};
struct softirq_t softirq_vector[MAX_SOFTIRQ_NUM] = {0};
/**
* @brief
*

View File

@ -176,6 +176,7 @@ void do_stack_segment_fault(struct pt_regs *regs, unsigned long error_code)
kerror("do_stack_segment_fault(12),\tError Code:%#18lx,\tRSP:%#18lx,\tRIP:%#18lx\t CPU:%d\n", error_code, regs->rsp,
regs->rip, proc_current_cpu_id);
// kinfo("cs=%#04x, ds=%#04x, ss=%#04x", regs->cs, regs->ds, regs->ss);
traceback(regs);
current_pcb->state = PROC_STOPPED;
sched();

View File

@ -17,6 +17,7 @@ void mutex_init(mutex_t *lock)
static void __mutex_sleep()
{
current_pcb->state = PROC_UNINTERRUPTIBLE;
current_pcb->flags |= PF_NEED_SCHED;
sched();
}
@ -71,7 +72,7 @@ void mutex_unlock(mutex_t *lock)
{
if (unlikely(!mutex_is_locked(lock)))
return;
spin_lock(&lock->wait_lock);
struct mutex_waiter_t *wt = NULL;
if (mutex_is_locked(lock))

View File

@ -18,6 +18,7 @@ void semaphore_down(semaphore_t *sema)
list_append(&sema->wait_queue.wait_list, &wait.wait_list);
// 执行调度
current_pcb->flags |= PF_NEED_SCHED;
sched();
}
}

View File

@ -57,11 +57,12 @@ pub fn spin_unlock_irq(lock: *mut spinlock_t) {
sti();
}
#[derive(Debug)]
pub struct RawSpinlock(AtomicBool);
impl RawSpinlock {
/// @brief 初始化自旋锁
const INIT: RawSpinlock = RawSpinlock(AtomicBool::new(false));
pub const INIT: RawSpinlock = RawSpinlock(AtomicBool::new(false));
/// @brief 加锁
pub fn lock(&mut self) {

View File

@ -130,7 +130,7 @@ void system_initialize()
syscall_init();
io_mfence();
// 再初始化进程模块。顺序不能调转
sched_init();
// sched_init();
io_mfence();
timer_init();

View File

@ -1,2 +1,2 @@
pub mod allocator;
pub mod gfp;
pub mod gfp;

View File

@ -90,7 +90,7 @@ static struct process_control_block *__kthread_create_on_node(int (*thread_fn)(v
int len = vsnprintf(pcb_name, name_fmt, PCB_NAME_LEN, get_args);
if (len >= PCB_NAME_LEN)
{
//名字过大 放到full_name字段中
// 名字过大 放到full_name字段中
struct kthread_info_t *kthread = to_kthread(pcb);
char *full_name = kzalloc(1024, 0);
vsprintf(full_name, name_fmt, get_args);
@ -173,7 +173,7 @@ static int kthread(void *_create)
// 将当前pcb返回给创建者
create->result = current_pcb;
current_pcb->state &= ~PROC_RUNNING; // 设置当前进程不是RUNNING态
current_pcb->state &= ~PROC_RUNNING; // 设置当前进程不是RUNNING态
io_mfence();
// 发起调度使得当前内核线程休眠。直到创建者通过process_wakeup将当前内核线程唤醒
@ -200,6 +200,8 @@ static void __create_kthread(struct kthread_create_info_t *create)
}
}
#pragma GCC push_options
#pragma GCC optimize("O0")
/**
* @brief kthread守护线程
*
@ -208,6 +210,7 @@ static void __create_kthread(struct kthread_create_info_t *create)
*/
int kthreadd(void *unused)
{
barrier();
kinfo("kthread daemon started!");
struct process_control_block *pcb = current_pcb;
kthreadd_pcb = current_pcb;
@ -237,8 +240,11 @@ int kthreadd(void *unused)
}
spin_unlock(&__kthread_create_lock);
}
barrier();
}
#pragma GCC pop_options
/**
* @brief 线退
*

View File

@ -3,6 +3,7 @@
#include <DragonOS/signal.h>
#include <common/wait_queue.h>
#include <DragonOS/stdint.h>
#include "ptrace.h"
// 进程最大可拥有的文件描述符数量
#define PROC_MAX_FD_NUM 16
@ -128,6 +129,7 @@ struct process_control_block
sigset_t sig_blocked;
// 正在等待的信号的标志位,表示某个信号正在等待处理
struct sigpending sig_pending;
};
// 将进程的pcb和内核栈融合到一起,8字节对齐

View File

@ -219,4 +219,5 @@ extern int process_try_to_wake_up(struct process_control_block *_pcb, uint64_t _
* @return true
* @return false
*/
extern int process_wake_up_state(struct process_control_block *pcb, uint64_t state);
extern int process_wake_up_state(struct process_control_block *pcb, uint64_t state);
void __switch_to(struct process_control_block *prev, struct process_control_block *next);

View File

@ -3,9 +3,9 @@ use core::ptr::{read_volatile, write_volatile};
use crate::{
arch::asm::current::current_pcb,
include::bindings::bindings::{
process_control_block, sched_enqueue, PROC_RUNNING, PROC_STOPPED,
process_control_block, PROC_RUNNING, PROC_STOPPED,
},
sched::core::cpu_executing,
sched::core::{cpu_executing, sched_enqueue},
smp::core::{smp_get_processor_id, smp_send_reschedule},
};
@ -76,7 +76,6 @@ pub extern "C" fn process_wake_up_state(pcb: *mut process_control_block, state:
return process_try_to_wake_up(pcb, state, 0);
}
/// @brief 让一个正在cpu上运行的进程陷入内核
pub fn process_kick(pcb: *mut process_control_block) {
preempt_disable();
@ -99,5 +98,5 @@ pub fn process_cpu(pcb: *const process_control_block) -> u32 {
/// @param pcb 进程的pcb
#[inline]
pub fn process_is_executing(pcb: *const process_control_block) -> bool {
return cpu_executing(process_cpu(pcb)) == pcb;
return cpu_executing(process_cpu(pcb)) as *const process_control_block == pcb;
}

View File

@ -2,10 +2,6 @@
#define __PTRACE_H__
/*
*/
struct pt_regs
{
unsigned long r15;
@ -36,9 +32,9 @@ struct pt_regs
/**
* @brief pt_regs是否来自用户态
*
* @param regs
* @return __always_inline
*
* @param regs
* @return __always_inline
*/
static inline int user_mode(struct pt_regs *regs)
{

View File

@ -1,163 +0,0 @@
#include "cfs.h"
#include <common/kprint.h>
#include <common/spinlock.h>
#include <driver/video/video.h>
struct sched_queue_t sched_cfs_ready_queue[MAX_CPU_NUM]; // 就绪队列
/**
* @brief PCB
*
* @return struct process_control_block*
*/
struct process_control_block *sched_cfs_dequeue()
{
if (list_empty(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list))
{
// kdebug("list empty, count=%d", sched_cfs_ready_queue[proc_current_cpu_id].count);
return &initial_proc_union.pcb;
}
struct process_control_block *proc = container_of(
list_next(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list), struct process_control_block, list);
list_del(&proc->list);
--sched_cfs_ready_queue[proc_current_cpu_id].count;
return proc;
}
/**
* @brief PCB加入就绪队列
*
* @param pcb
*/
void sched_cfs_enqueue(struct process_control_block *pcb)
{
if (pcb == initial_proc[proc_current_cpu_id])
return;
struct process_control_block *proc = container_of(
list_next(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list), struct process_control_block, list);
if ((list_empty(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list)) == 0)
{
while (proc->virtual_runtime < pcb->virtual_runtime)
{
proc = container_of(list_next(&proc->list), struct process_control_block, list);
}
}
list_append(&proc->list, &pcb->list);
++sched_cfs_ready_queue[proc_current_cpu_id].count;
}
/**
* @brief
*
*/
void sched_cfs()
{
cli();
current_pcb->flags &= ~PF_NEED_SCHED;
// kdebug("current_pcb pid= %d", current_pcb->pid);
struct process_control_block *proc = sched_cfs_dequeue();
// kdebug("sched_cfs_ready_queue[proc_current_cpu_id].count = %d",
// sched_cfs_ready_queue[proc_current_cpu_id].count);
if (current_pcb->virtual_runtime >= proc->virtual_runtime ||
!(current_pcb->state & PROC_RUNNING)) // 当前进程运行时间大于了下一进程的运行时间,进行切换
{
// kdebug("current_pcb->virtual_runtime = %d,proc->vt= %d", current_pcb->virtual_runtime,
// proc->virtual_runtime);
if (current_pcb->state &
PROC_RUNNING) // 本次切换由于时间片到期引发,则再次加入就绪队列,否则交由其它功能模块进行管理
sched_cfs_enqueue(current_pcb);
// kdebug("proc->pid=%d, count=%d", proc->pid, sched_cfs_ready_queue[proc_current_cpu_id].count);
if (sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies <= 0)
{
switch (proc->priority)
{
case 0:
case 1:
sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies =
4 / sched_cfs_ready_queue[proc_current_cpu_id].count;
break;
case 2:
default:
sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies =
(4 / sched_cfs_ready_queue[proc_current_cpu_id].count) << 2;
break;
}
}
barrier();
switch_proc(current_pcb, proc);
barrier();
}
else // 不进行切换
{
// kdebug("not switch.");
sched_cfs_enqueue(proc);
if (sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies <= 0)
{
switch (proc->priority)
{
case 0:
case 1:
sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies =
4 / sched_cfs_ready_queue[proc_current_cpu_id].count;
break;
case 2:
default:
sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies =
(4 / sched_cfs_ready_queue[proc_current_cpu_id].count) << 2;
break;
}
}
}
sti();
}
/**
* @brief
*
*/
void sched_update_jiffies()
{
switch (current_pcb->priority)
{
case 0:
case 1:
--sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies;
++current_pcb->virtual_runtime;
break;
case 2:
default:
sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies -= 2;
current_pcb->virtual_runtime += 2;
break;
}
// 时间片耗尽,标记可调度
if (sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies <= 0)
current_pcb->flags |= PF_NEED_SCHED;
}
/**
* @brief CFS调度器
*
*/
void sched_cfs_init()
{
memset(&sched_cfs_ready_queue, 0, sizeof(struct sched_queue_t) * MAX_CPU_NUM);
for (int i = 0; i < MAX_CPU_NUM; ++i)
{
list_init(&sched_cfs_ready_queue[i].proc_queue.list);
sched_cfs_ready_queue[i].count = 1; // 因为存在IDLE进程因此为1
sched_cfs_ready_queue[i].cpu_exec_proc_jiffies = 5;
sched_cfs_ready_queue[i].proc_queue.virtual_runtime = 0x7fffffffffffffff;
}
}

201
kernel/src/sched/cfs.rs Normal file
View File

@ -0,0 +1,201 @@
use core::{
ptr::null_mut,
sync::atomic::compiler_fence,
};
use alloc::{boxed::Box, vec::Vec};
use crate::{
arch::{
asm::current::current_pcb,
context::switch_process,
},
include::bindings::bindings::{
initial_proc_union, process_control_block, MAX_CPU_NUM, PF_NEED_SCHED,
PROC_RUNNING,
},
kBUG,
libs::spinlock::RawSpinlock,
};
use super::core::Scheduler;
/// 声明全局的cfs调度器实例
pub static mut CFS_SCHEDULER_PTR: *mut SchedulerCFS = null_mut();
/// @brief 获取cfs调度器实例的可变引用
#[inline]
pub fn __get_cfs_scheduler() -> &'static mut SchedulerCFS {
return unsafe { CFS_SCHEDULER_PTR.as_mut().unwrap() };
}
/// @brief 初始化cfs调度器
pub unsafe fn sched_cfs_init() {
if CFS_SCHEDULER_PTR.is_null() {
CFS_SCHEDULER_PTR = Box::leak(Box::new(SchedulerCFS::new()));
} else {
kBUG!("Try to init CFS Scheduler twice.");
panic!("Try to init CFS Scheduler twice.");
}
}
/// @brief CFS队列per-cpu的
#[derive(Debug)]
struct CFSQueue {
/// 当前cpu上执行的进程剩余的时间片
cpu_exec_proc_jiffies: i64,
/// 队列的锁
lock: RawSpinlock,
/// 进程的队列
queue: Vec<&'static mut process_control_block>,
}
impl CFSQueue {
pub fn new() -> CFSQueue {
CFSQueue {
cpu_exec_proc_jiffies: 0,
lock: RawSpinlock::INIT,
queue: Vec::new(),
}
}
/// @brief 将进程按照虚拟运行时间的升序进行排列
/// todo: 换掉这个sort方法因为它底层是归并很占内存且时间复杂度为nlogn遍历然后插入的方法时间复杂度最坏是n
pub fn sort(&mut self) {
self.queue
.sort_by(|a, b| (*a).virtual_runtime.cmp(&(*b).virtual_runtime));
}
/// @brief 将pcb加入队列
pub fn enqueue(&mut self, pcb: &'static mut process_control_block) {
self.lock.lock();
// 如果进程是IDLE进程那么就不加入队列
if pcb.pid == 0 {
self.lock.unlock();
return;
}
self.queue.push(pcb);
self.sort();
self.lock.unlock();
}
/// @brief 将pcb从调度队列中弹出,若队列为空则返回IDLE进程的pcb
pub fn dequeue(&mut self) -> &'static mut process_control_block {
let res: &'static mut process_control_block;
self.lock.lock();
if self.queue.len() > 0 {
// 队列不为空返回下一个要执行的pcb
res = self.queue.pop().unwrap();
} else {
// 如果队列为空则返回IDLE进程的pcb
res = unsafe { &mut initial_proc_union.pcb };
}
self.lock.unlock();
return res;
}
}
/// @brief CFS调度器类
pub struct SchedulerCFS {
cpu_queue: Vec<&'static mut CFSQueue>,
}
impl SchedulerCFS {
pub fn new() -> SchedulerCFS {
// 暂时手动指定核心数目
// todo: 从cpu模块来获取核心的数目
let mut result = SchedulerCFS {
cpu_queue: Default::default(),
};
// 为每个cpu核心创建队列
for _ in 0..MAX_CPU_NUM {
result.cpu_queue.push(Box::leak(Box::new(CFSQueue::new())));
}
return result;
}
/// @brief 更新这个cpu上这个进程的可执行时间。
#[inline]
fn update_cpu_exec_proc_jiffies(_priority: i64, cfs_queue: &mut CFSQueue) -> &mut CFSQueue {
// todo: 引入调度周期以及所有进程的优先权进行计算,然后设置分配给进程的可执行时间
cfs_queue.cpu_exec_proc_jiffies = 10;
return cfs_queue;
}
/// @brief 时钟中断到来时由sched的core模块中的函数调用本函数更新CFS进程的可执行时间
pub fn timer_update_jiffies(&mut self) {
let current_cpu_queue: &mut CFSQueue = self.cpu_queue[current_pcb().cpu_id as usize];
// todo: 引入调度周期以及所有进程的优先权进行计算,然后设置进程的可执行时间
// 更新进程的剩余可执行时间
current_cpu_queue.lock.lock();
current_cpu_queue.cpu_exec_proc_jiffies -= 1;
// 时间片耗尽,标记需要被调度
if current_cpu_queue.cpu_exec_proc_jiffies <= 0 {
current_pcb().flags |= PF_NEED_SCHED as u64;
}
current_cpu_queue.lock.unlock();
// 更新当前进程的虚拟运行时间
current_pcb().virtual_runtime += 1;
}
}
impl Scheduler for SchedulerCFS {
/// @brief 在当前cpu上进行调度。
/// 请注意,进入该函数之前,需要关中断
fn sched(&mut self) {
// kdebug!("cfs:sched");
current_pcb().flags &= !(PF_NEED_SCHED as u64);
let current_cpu_id = current_pcb().cpu_id as usize;
let current_cpu_queue: &mut CFSQueue = self.cpu_queue[current_cpu_id];
let proc: &'static mut process_control_block = current_cpu_queue.dequeue();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 如果当前不是running态或者当前进程的虚拟运行时间大于等于下一个进程的那就需要切换。
if (current_pcb().state & (PROC_RUNNING as u64)) == 0
|| current_pcb().virtual_runtime >= proc.virtual_runtime
{
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 本次切换由于时间片到期引发,则再次加入就绪队列,否则交由其它功能模块进行管理
if current_pcb().state & (PROC_RUNNING as u64) != 0 {
// kdebug!("cfs:sched->enqueue");
current_cpu_queue.enqueue(current_pcb());
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 设置进程可以执行的时间
if current_cpu_queue.cpu_exec_proc_jiffies <= 0 {
SchedulerCFS::update_cpu_exec_proc_jiffies(proc.priority, current_cpu_queue);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
switch_process(current_pcb(), proc);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
} else {
// 不进行切换
// 设置进程可以执行的时间
compiler_fence(core::sync::atomic::Ordering::SeqCst);
if current_cpu_queue.cpu_exec_proc_jiffies <= 0 {
SchedulerCFS::update_cpu_exec_proc_jiffies(proc.priority, current_cpu_queue);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
current_cpu_queue.enqueue(proc);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
fn enqueue(&mut self, pcb: &'static mut process_control_block) {
let cpu_queue = &mut self.cpu_queue[pcb.cpu_id as usize];
cpu_queue.enqueue(pcb);
}
}

14
kernel/src/sched/core.c Normal file
View File

@ -0,0 +1,14 @@
#include "sched.h"
/**
* @brief
* TODO使Rust重构这里
* @param prev pcb
* @param proc pcb
*/
void switch_proc(struct process_control_block *prev, struct process_control_block *proc)
{
process_switch_mm(proc);
io_mfence();
switch_to(prev, proc);
}

View File

@ -1,13 +1,85 @@
use crate::{include::bindings::bindings::process_control_block, process::process::process_cpu, arch::asm::current::current_pcb};
use core::sync::atomic::compiler_fence;
use crate::{
arch::asm::{current::current_pcb, ptrace::user_mode},
include::bindings::bindings::{process_control_block, pt_regs, EPERM, SCHED_NORMAL},
process::process::process_cpu,
};
use super::cfs::{sched_cfs_init, SchedulerCFS, __get_cfs_scheduler};
/// @brief 获取指定的cpu上正在执行的进程的pcb
#[inline]
pub fn cpu_executing(cpu_id:u32) -> *const process_control_block{
pub fn cpu_executing(cpu_id: u32) -> &'static mut process_control_block {
// todo: 引入per_cpu之后该函数真正执行“返回指定的cpu上正在执行的pcb”的功能
if cpu_id == process_cpu(current_pcb()){
if cpu_id == process_cpu(current_pcb()) {
return current_pcb();
}else {
} else {
todo!()
}
}
}
/// @brief 具体的调度器应当实现的trait
pub trait Scheduler {
/// @brief 使用该调度器发起调度的时候,要调用的函数
fn sched(&mut self);
/// @brief 将pcb加入这个调度器的调度队列
fn enqueue(&mut self, pcb: &'static mut process_control_block);
}
fn __sched() {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let cfs_scheduler: &mut SchedulerCFS = __get_cfs_scheduler();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
cfs_scheduler.sched();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
/// @brief 将进程加入调度队列
#[allow(dead_code)]
#[no_mangle]
pub extern "C" fn sched_enqueue(pcb: &'static mut process_control_block) {
let cfs_scheduler = __get_cfs_scheduler();
cfs_scheduler.enqueue(pcb);
}
/// @brief 初始化进程调度器模块
#[allow(dead_code)]
#[no_mangle]
pub extern "C" fn sched_init() {
unsafe {
sched_cfs_init();
}
}
/// @brief 当时钟中断到达时,更新时间片
/// 请注意,该函数只能被时钟中断处理程序调用
#[allow(dead_code)]
#[no_mangle]
pub extern "C" fn sched_update_jiffies() {
match current_pcb().policy {
SCHED_NORMAL => {
__get_cfs_scheduler().timer_update_jiffies();
}
_ => {
todo!()
}
}
}
/// @brief 让系统立即运行调度器的系统调用
/// 请注意该系统调用不能由ring3的程序发起
#[allow(dead_code)]
#[no_mangle]
pub extern "C" fn sys_sched(regs: &'static mut pt_regs) -> u64 {
// 进行权限校验,拒绝用户态发起调度
if user_mode(regs) {
return (-(EPERM as i64)) as u64;
}
__sched();
0
}

View File

@ -1 +1,2 @@
pub mod core;
pub mod core;
pub mod cfs;

View File

@ -1,95 +0,0 @@
#include "sched.h"
#include <common/kprint.h>
#include <common/spinlock.h>
#include <common/string.h>
#include <driver/video/video.h>
#include <sched/cfs.h>
/**
* @brief
*
* @param p pcb
* @param attr
* @param user
* @param pi
* @return int
*/
static int __sched_setscheduler(struct process_control_block *p, const struct sched_attr *attr, bool user, bool pi)
{
int policy = attr->sched_policy;
recheck:;
// 这里policy的设置小于0是因为需要在临界区内更新值之后重新到这里判断
if (!IS_VALID_SCHED_POLICY(policy))
{
return -EINVAL;
}
// 修改成功
p->policy = policy;
return 0;
}
static int _sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param, bool check)
{
struct sched_attr attr = {.sched_policy = policy};
return __sched_setscheduler(p, &attr, check, true);
}
/**
* sched_setscheduler -
* @param p pcb
* @param policy policy
* @param param structure containing the new RT priority.
*
* @return 0,
*
*/
int sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param)
{
return _sched_setscheduler(p, policy, param, true);
}
/**
* @brief shced_cfs_enqueue(),PCB加入就绪队列
*
* @param pcb
*/
void sched_enqueue(struct process_control_block *pcb)
{
sched_cfs_enqueue(pcb);
}
/**
* @brief sys_sched调用
*
*/
static void __sched()
{
sched_cfs();
}
void sched_init()
{
sched_cfs_init();
}
uint64_t sys_sched(struct pt_regs *regs)
{
if(user_mode(regs)){
return -EPERM;
}
__sched();
}
void sched()
{
enter_syscall_int(SYS_SCHED, 0, 0, 0, 0, 0, 0, 0, 0);
}
void switch_proc(struct process_control_block *prev, struct process_control_block *proc)
{
process_switch_mm(proc);
io_mfence();
switch_to(prev, proc);
}

View File

@ -17,64 +17,61 @@
#define IS_VALID_SCHED_POLICY(_policy) ((_policy) > 0 && (_policy) <= SCHED_MAX_POLICY_NUM)
struct sched_param
{
int sched_priority;
};
struct sched_attr
{
uint32_t size;
uint32_t sched_policy;
uint64_t sched_flags;
/* SCHED_NORMAL, SCHED_BATCH */
int32_t sched_nice;
// struct sched_param
// {
// int sched_priority;
// };
// struct sched_attr
// {
// uint32_t size;
/* SCHED_FIFO, SCHED_RR */
uint32_t sched_priority;
// uint32_t sched_policy;
// uint64_t sched_flags;
/* SCHED_DEADLINE */
uint64_t sched_runtime;
uint64_t sched_deadline;
uint64_t sched_period;
// /* SCHED_NORMAL, SCHED_BATCH */
// int32_t sched_nice;
/* Utilization hints */
uint32_t sched_util_min;
uint32_t sched_util_max;
};
// /* SCHED_FIFO, SCHED_RR */
// uint32_t sched_priority;
// /* SCHED_DEADLINE */
// uint64_t sched_runtime;
// uint64_t sched_deadline;
// uint64_t sched_period;
// /* Utilization hints */
// uint32_t sched_util_min;
// uint32_t sched_util_max;
// };
// static int __sched_setscheduler(struct process_control_block *p, const struct sched_attr *attr, bool user, bool pi);
// static int _sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param,
// bool check);
// /**
// * sched_setscheduler -设置进程的调度策略
// * @param p 需要修改的pcb
// * @param policy 需要设置的policy
// * @param param structure containing the new RT priority. 目前没有用
// *
// * @return 成功返回0,否则返回对应的错误码
// *
// */
// int sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param);
static int __sched_setscheduler(struct process_control_block *p, const struct sched_attr *attr, bool user, bool pi);
static int _sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param,
bool check);
/**
* sched_setscheduler -
* @param p pcb
* @param policy policy
* @param param structure containing the new RT priority.
*
* @return 0,
*
*/
int sched_setscheduler(struct process_control_block *p, int policy, const struct sched_param *param);
/**
* @brief sched_enqueue(),PCB加入就绪队列
*
* @param pcb
*/
void sched_enqueue(struct process_control_block *pcb);
/**
* @brief sched_cfs()
*
*/
void sched();
void sched_init();
// ================= Rust 实现 =============
extern void sched_update_jiffies();
extern void sched_init();
extern void sched();
extern void sched_enqueue(struct process_control_block *pcb);
extern void sched();
/**
* @brief
*
*/
void sched_update_jiffies();
void switch_proc(struct process_control_block *prev, struct process_control_block *proc);
void switch_proc(struct process_control_block *prev, struct process_control_block *proc);

View File

@ -12,8 +12,6 @@
#include "ipi.h"
void ipi_0xc8_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs); // 由BSP转发的HPET中断处理函数
static spinlock_t multi_core_starting_lock = {1}; // 多核启动锁
static struct acpi_Processor_Local_APIC_Structure_t *proc_local_apic_structs[MAX_SUPPORTED_PROCESSOR_NUM];
@ -47,8 +45,6 @@ void smp_init()
io_mfence();
// 注册接收bsp处理器的hpet中断转发的处理函数
ipi_regiserIPI(0xc8, NULL, &ipi_0xc8_handler, NULL, NULL, "IPI 0xc8");
io_mfence();
ipi_send_IPI(DEST_PHYSICAL, IDLE, ICR_LEVEL_DE_ASSERT, EDGE_TRIGGER, 0x00, ICR_INIT, ICR_ALL_EXCLUDE_Self, 0x00);
@ -193,9 +189,3 @@ void smp_ap_start()
while (1) // 这里要循环hlt原因是当收到中断后核心会被唤醒处理完中断之后不会自动hlt
hlt();
}
// 由BSP转发的HPET中断处理函数
void ipi_0xc8_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs)
{
sched_update_jiffies();
}

View File

@ -12,7 +12,6 @@
#include <process/process.h>
#include <time/sleep.h>
// 导出系统调用入口函数定义在entry.S中
extern void system_call(void);
extern void syscall_int(void);
extern uint64_t sys_clock(struct pt_regs *regs);

View File

@ -33,7 +33,6 @@ void syscall_init();
* @param syscall_id id
* @return long
*/
long enter_syscall(ul syscall_id, ul arg0, ul arg1, ul arg2, ul arg3, ul arg4, ul arg5, ul arg6, ul arg7);
long enter_syscall_int(ul syscall_id, ul arg0, ul arg1, ul arg2, ul arg3, ul arg4, ul arg5, ul arg6, ul arg7);
/**