doc: Add ai doc translate tool and add English doc. (#1168)

- add tools/doc_translator.py
- translated docs into English

Signed-off-by: longjin <longjin@DragonOS.org>
This commit is contained in:
LoGin
2025-05-20 10:44:28 +08:00
committed by GitHub
parent fccfa6f7ff
commit 880720250e
98 changed files with 13972 additions and 6 deletions

View File

@ -0,0 +1,26 @@
.. note:: AI Translation Notice
This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only.
- Source document: kernel/locking/index.rst
- Translation time: 2025-05-19 01:41:08
- Translation model: `Qwen/Qwen3-8B`
Please report issues via `Community Channel <https://github.com/DragonOS-Community/DragonOS/issues>`_
====================================
Locks
====================================
This is the documentation explaining the lock variables in DragonOS.
.. toctree::
:maxdepth: 1
locks
spinlock
mutex
rwlock

View File

@ -0,0 +1,63 @@
:::{note}
**AI Translation Notice**
This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only.
- Source document: kernel/locking/locks.md
- Translation time: 2025-05-19 01:41:26
- Translation model: `Qwen/Qwen3-8B`
Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues)
:::
# Types of Locks and Their Rules
## Introduction
&emsp;&emsp;The DragonOS kernel implements several types of locks, which can be broadly categorized into two types:
- Sleepable locks
- Spin locks
## Types of Locks
### Sleepable Locks
&emsp;&emsp;Sleepable locks can only be acquired in a context that is preemptible.
&emsp;&emsp;In DragonOS, the following sleepable locks are implemented:
- semaphore
- mutex_t
### Spin Locks
- spinlock_t
- {ref}`RawSpinLock <_spinlock_doc_rawspinlock>` (Rust version of spinlock_t, but incompatible with spinlock_t)
- {ref}`SpinLock <_spinlock_doc_spinlock>` —— Built on top of RawSpinLock, it wraps a guard, binding the lock and the data it protects into a single structure. This allows for compile-time checks to prevent accessing data without holding the lock.
&emsp;&emsp;When a process acquires a spin lock, it changes the lock count in the PCB, thereby implicitly disabling preemption. To provide more flexible operations, spinlock also provides the following methods:
| Suffix | Description |
|----------------------|--------------------------------------------------------|
| _irq() | Disable interrupts when acquiring the lock, enable them when releasing |
| _irqsave()/_irqrestore() | Save the interrupt state when acquiring the lock, and restore it when releasing |
## Detailed Introduction
### Detailed Introduction to Spin Locks
&emsp;&emsp;For a detailed introduction to spin locks, please refer to the document: {ref}`自旋锁 <_spinlock_doc>`
### Semaphore
&emsp;&emsp;A semaphore is implemented based on a counter.
&emsp;&emsp;When the available resources are insufficient, a process attempting to perform a down operation on the semaphore will be put to sleep until the resources become available.
### Mutex
&emsp;&emsp;Please refer to {ref}`Mutex文档 <_mutex_doc>`

View File

@ -0,0 +1,185 @@
:::{note}
**AI Translation Notice**
This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only.
- Source document: kernel/locking/mutex.md
- Translation time: 2025-05-19 01:41:16
- Translation model: `Qwen/Qwen3-8B`
Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues)
:::
(_translated_label___mutex_doc_en)=
:::{note}
Author: Longjin <longjin@RinGoTek.cn>
:::
# Mutex (Mutual Exclusion)
&emsp;&emsp;A mutex is a lightweight synchronization primitive, with only two states: locked and idle.
&emsp;&emsp;When a mutex is occupied, any process attempting to lock it will be put to sleep until the resource becomes available.
## 1. Features
- Only one task can hold the mutex at a time.
- Recursive locking and unlocking are not allowed.
- Mutex can only be operated through its API.
- Mutex cannot be used in hard interrupts or soft interrupts.
## 2. Definition
&emsp;&emsp;The mutex is defined in `lib/mutex.rs`, as shown below:
```rust
/// @brief Mutex互斥量结构体
/// 请注意由于Mutex属于休眠锁因此如果您的代码可能在中断上下文内执行请勿采用Mutex
#[derive(Debug)]
pub struct Mutex<T> {
/// 该Mutex保护的数据
data: UnsafeCell<T>,
/// Mutex内部的信息
inner: SpinLock<MutexInner>,
}
#[derive(Debug)]
struct MutexInner {
/// 当前Mutex是否已经被上锁(上锁时为true)
is_locked: bool,
/// 等待获得这个锁的进程的链表
wait_list: LinkedList<&'static mut process_control_block>,
}
```
## 3. Usage
&emsp;&emsp;Similar to SpinLock, the Rust version of Mutex has a guard. When using it, you need to transfer the ownership of the data to be protected to the Mutex. Moreover, the guard can only be generated after a successful lock, so at any moment, each Mutex can have at most one guard.
&emsp;&emsp;When you need to read or modify the data protected by the Mutex, you should first use the `lock()` method of the Mutex. This method returns a `MutexGuard`. You can use the member functions of the protected data to perform some operations, or directly read or write the protected data. (This is equivalent to obtaining a mutable reference to the protected data.)
&emsp;&emsp;A complete example is shown in the code below:
```rust
let x :Mutex<Vec<i32>>= Mutex::new(Vec::new());
{
let mut g :MutexGuard<Vec<i32>>= x.lock();
g.push(1);
g.push(2);
g.push(2);
assert!(g.as_slice() == [1, 2, 2] || g.as_slice() == [2, 2, 1]);
// 在此处Mutex是加锁的状态
debug!("x={:?}", x);
}
// 由于上方的变量`g`也就是Mutex守卫的生命周期结束自动释放了Mutex。因此在此处Mutex是放锁的状态
debug!("x={:?}", x);
```
&emsp;&emsp;For variables inside a structure, we can use Mutex to perform fine-grained locking, that is, wrap the member variables that need to be locked in detail with Mutex, for example:
```rust
pub struct a {
pub data: Mutex<data_struct>,
}
```
&emsp;&emsp;Of course, we can also lock the entire structure:
```rust
struct MyStruct {
pub data: data_struct,
}
/// 被全局加锁的结构体
pub struct LockedMyStruct(Mutex<MyStruct>);
```
## 4. API
### 4.1. new - Initialize Mutex
#### Prototype
```rust
pub const fn new(value: T) -> Self
```
#### Description
&emsp;&emsp;The `new()` method is used to initialize a Mutex. This method requires a protected data as a parameter. It returns a Mutex.
### 4.2. lock - Lock
#### Prototype
```rust
pub fn lock(&self) -> MutexGuard<T>
```
#### Description
&emsp;&emsp;Lock the Mutex, returns the guard of the Mutex. You can use this guard to operate the protected data.
&emsp;&emsp;If the Mutex is already locked, this method will block the current process until the Mutex is released.
### 4.3. try_lock - Try to Lock
#### Prototype
```rust
pub fn try_lock(&self) -> Result<MutexGuard<T>, i32>
```
#### Description
&emsp;&emsp;Try to lock the Mutex. If the lock fails, the current process will not be added to the waiting queue. If the lock is successful, it returns the guard of the Mutex; if the Mutex is already locked, it returns `Err(错误码)`.
## 5. C Version of Mutex (Will be deprecated in the future)
&emsp;&emsp;The mutex is defined in `common/mutex.h`. Its data type is as follows:
```c
typedef struct
{
atomic_t count; // 锁计数。1->已解锁。 0->已上锁,且有可能存在等待者
spinlock_t wait_lock; // mutex操作锁用于对mutex的list的操作进行加锁
struct List wait_list; // Mutex的等待队列
} mutex_t;
```
### 5.1. API
#### mutex_init
**`void mutex_init(mutex_t *lock)`**
&emsp;&emsp;Initialize a mutex object.
#### mutex_lock
**`void mutex_lock(mutex_t *lock)`**
&emsp;&emsp;Lock a mutex object. If the mutex is currently held by another process, the current process will enter a sleep state.
#### mutex_unlock
**`void mutex_unlock(mutex_t *lock)`**
&emsp;&emsp;Unlock a mutex object. If there are other processes in the mutex's waiting queue, the next process will be awakened.
#### mutex_trylock
**`void mutex_trylock(mutex_t *lock)`**
&emsp;&emsp;Try to lock a mutex object. If the mutex is currently held by another process, it returns 0. Otherwise, the lock is successful and returns 1.
#### mutex_is_locked
**`void mutex_is_locked(mutex_t *lock)`**
&emsp;&emsp;Determine if the mutex is already locked. If the given mutex is in a locked state, it returns 1; otherwise, it returns 0.

View File

@ -0,0 +1,216 @@
:::{note}
**AI Translation Notice**
This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only.
- Source document: kernel/locking/rwlock.md
- Translation time: 2025-05-19 01:41:57
- Translation model: `Qwen/Qwen3-8B`
Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues)
:::
# RwLock Read-Write Lock
:::{note}
Author: sujintao
Email: <sujintao@dragonos.org>
:::
## 1. Introduction
&emsp;&emsp;A read-write lock is a mechanism used in a concurrent environment to protect shared data among multiple processes. Compared to a regular spinlock, a read-write lock divides access to shared data into two types: read access and write access. Read access to shared data is controlled by a read lock, while write access to shared data is controlled by a write lock. The design of a read-write lock allows for multiple "readers" (read-only access) and a single "writer" (write access) to coexist simultaneously. For shared data that is mostly read-only, using a read-write lock to control access can improve performance to some extent.
## 2. Implementation of Read-Write Lock in DragonOS
### 2.1 Mechanism of Read-Write Lock
&emsp;&emsp;The purpose of a read-write lock is to maintain the consistency of shared variables in a multi-threaded system. Data is wrapped in an RwLock data structure, and all access and modification must be done through this structure. Each process that accesses shared data will obtain a guard. A read-only process obtains a READER (reader guard), while a process that needs to modify a shared variable obtains a WRITER (writer guard). As a "shadow" of the RwLock, threads perform access and modification operations based on the guard.
&emsp;&emsp;In practice, in addition to READER and WRITER, a read-write lock also introduces an UPGRADER. This is a guard that lies between READER and WRITER. The role of the UPGRADER is to prevent WRITER starvation. When a process obtains an UPGRADER, it treats it as a READER. However, the UPGRADER can be upgraded, and after upgrading, it becomes a WRITER guard, allowing write operations on shared data.
&emsp;&emsp;All guards satisfy the RAII mechanism native to Rust. When the scope of a guard ends, the guard will automatically release.
### 2.2 Relationship Between Read-Write Lock Guards
&emsp;&emsp;At any given time, multiple READERS can exist, meaning that multiple processes can access shared data simultaneously. However, only one WRITER can exist at a time, and when a process obtains a WRITER, no READERS or UPGRADERS can exist. A process can obtain an UPGRADER only if there are no existing UPGRADERS or WRITERS. However, once a process obtains an UPGRADER, it cannot successfully apply for a READER.
### 2.3 Design Details
#### 2.3.1 RwLock Data Structure
```rust
pub struct RwLock<T> {
lock: AtomicU32,//原子变量
data: UnsafeCell<T>,
}
```
#### 2.3.2 READER Guard Data Structure
```rust
pub struct RwLockReadGuard<'a, T: 'a> {
data: *const T,
lock: &'a AtomicU32,
}
```
#### 2.3.3 UPGRADER Guard Data Structure
```rust
pub struct RwLockUpgradableGuard<'a, T: 'a> {
data: *const T,
inner: &'a RwLock<T>,
}
```
#### 2.3.4 WRITER Guard Data Structure
```rust
pub struct RwLockWriteGuard<'a, T: 'a> {
data: *mut T,
inner: &'a RwLock<T>,
}
```
#### 2.3.5 Introduction to the lock Structure in RwLock
The lock is a 32-bit atomic variable AtomicU32, and its bit allocation is as follows:
```
UPGRADER_BIT WRITER_BIT
^ ^
OVERFLOW_BIT +------+ +-------+
^ | |
| | |
+-+--+--------------------------------------------------------+-+--+-+--+
| | | | |
| | | | |
| | The number of the readers | | |
| | | | |
+----+--------------------------------------------------------+----+----+
31 30 2 1 0
```
&emsp;&emsp;(From right to left) The 0th bit represents whether WRITER is valid. If WRITER_BIT = 1, it indicates that a process has obtained a WRITER guard. If UPGRADER_BIT = 1, it indicates that a process has obtained an UPGRADER guard. Bits 2 to 30 are used to represent the number of processes that have obtained READER guards in binary form. The 31st bit is an overflow detection bit. If OVERFLOW_BIT = 1, new requests for obtaining READER guards will be rejected.
## 3. Main APIs of Read-Write Lock
### 3.1 Main APIs of RwLock
```rust
///功能: 输入需要保护的数据类型data,返回一个新的RwLock类型.
pub const fn new(data: T) -> Self
```
```rust
///功能: 获得READER守卫
pub fn read(&self) -> RwLockReadGuard<T>
```
```rust
///功能: 尝试获得READER守卫
pub fn try_read(&self) -> Option<RwLockReadGuard<T>>
```
```rust
///功能: 获得WRITER守卫
pub fn write(&self) -> RwLockWriteGuard<T>
```
```rust
///功能: 尝试获得WRITER守卫
pub fn try_write(&self) -> Option<RwLockWriteGuard<T>>
```
```rust
///功能: 获得UPGRADER守卫
pub fn upgradeable_read(&self) -> RwLockUpgradableGuard<T>
```
```rust
///功能: 尝试获得UPGRADER守卫
pub fn try_upgradeable_read(&self) -> Option<RwLockUpgradableGuard<T>>
```
### 3.2 Main APIs of the WRITER Guard RwLockWriteGuard
```rust
///功能: 将WRITER降级为READER
pub fn downgrade(self) -> RwLockReadGuard<'rwlock, T>
```
```rust
///功能: 将WRITER降级为UPGRADER
pub fn downgrade_to_upgradeable(self) -> RwLockUpgradableGuard<'rwlock, T>
```
### 3.3 Main APIs of the UPGRADER Guard RwLockUpgradableGuard
```rust
///功能: 将UPGRADER升级为WRITER
pub fn upgrade(mut self) -> RwLockWriteGuard<'rwlock, T>
```
```rust
///功能: 将UPGRADER降级为READER
pub fn downgrade(self) -> RwLockReadGuard<'rwlock, T>
```
## 4. Usage Examples
```rust
static LOCK: RwLock<u32> = RwLock::new(100 as u32);
fn t_read1() {
let guard = LOCK.read();
let value = *guard;
let readers_current = LOCK.reader_count();
let writers_current = LOCK.writer_count();
println!(
"Reader1: the value is {value}
There are totally {writers_current} writers, {readers_current} readers"
);
}
fn t_read2() {
let guard = LOCK.read();
let value = *guard;
let readers_current = LOCK.reader_count();
let writers_current = LOCK.writer_count();
println!(
"Reader2: the value is {value}
There are totally {writers_current} writers, {readers_current} readers"
);
}
fn t_write() {
let mut guard = LOCK.write();
*guard += 100;
let writers_current = LOCK.writer_count();
let readers_current = LOCK.reader_count();
println!(
"Writers: the value is {guard}
There are totally {writers_current} writers, {readers_current} readers",
guard = *guard
);
let read_guard=guard.downgrade();
let value=*read_guard;
println!("After downgraded to read_guard: {value}");
}
fn t_upgrade() {
let guard = LOCK.upgradeable_read();
let value = *guard;
let readers_current = LOCK.reader_count();
let writers_current = LOCK.writer_count();
println!(
"Upgrader1 before upgrade: the value is {value}
There are totally {writers_current} writers, {readers_current} readers"
);
let mut upgraded_guard = guard.upgrade();
*upgraded_guard += 100;
let writers_current = LOCK.writer_count();
let readers_current = LOCK.reader_count();
println!(
"Upgrader1 after upgrade: the value is {temp}
There are totally {writers_current} writers, {readers_current} readers",
temp = *upgraded_guard
);
let downgraded_guard=upgraded_guard.downgrade_to_upgradeable();
let value=*downgraded_guard;
println!("value after downgraded: {value}");
let read_guard=downgraded_guard.downgrade();
let value_=*read_guard;
println!("value after downgraded to read_guard: {value_}");
}
fn main() {
let r2=thread::spawn(t_read2);
let r1 = thread::spawn(t_read1);
let t1 = thread::spawn(t_write);
let g1 = thread::spawn(t_upgrade);
r1.join().expect("r1");
t1.join().expect("t1");
g1.join().expect("g1");
r2.join().expect("r2");
}
```

View File

@ -0,0 +1,118 @@
:::{note}
**AI Translation Notice**
This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only.
- Source document: kernel/locking/spinlock.md
- Translation time: 2025-05-19 01:43:03
- Translation model: `Qwen/Qwen3-8B`
Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues)
:::
(_translated_label___spinlock_doc_en)=
:::{note}
Author: Longjin <longjin@RinGoTek.cn>
:::
# Spinlock
## 1. Introduction
&emsp;&emsp;A spinlock is a type of lock used for synchronization in multi-threaded environments. Threads repeatedly check if the lock variable is available. Since the thread remains in a running state during this process, it is a form of busy waiting. Once a spinlock is acquired, the thread will hold onto it until it is explicitly released.
&emsp;&emsp;DragonOS implements spinlocks in the `kernel/src/lib/spinlock.rs` file. Based on slight differences in functional characteristics, two types of spinlocks, `RawSpinLock` and `SpinLock`, are provided.
(_translated_label___spinlock_doc_rawspinlock_en)=
## 2. RawSpinLock - Raw Spinlock
&emsp;&emsp;`RawSpinLock` is a raw spinlock, whose data part contains an AtomicBool, implementing the basic functionality of a spinlock. Its locking and unlocking require manual determination of the corresponding timing, meaning that, like spinlocks used in other languages, you need to first call the `lock()` method, and then manually call the `unlock()` method when leaving the critical section. We do not explicitly inform the compiler of which data the spinlock is protecting.
&emsp;&emsp;RawSpinLock provides programmers with very flexible control over locking and unlocking. However, due to its excessive flexibility, it is easy to make mistakes when using it. Common issues include "accessing critical section data without locking", "forgetting to unlock", and "double unlocking". The compiler cannot check for these issues, and they can only be discovered at runtime.
:::{warning}
`RawSpinLock` is not binary compatible with the C version of `spinlock_t`. If you need to operate on the C version of `spinlock_t` for temporary compatibility reasons, please use the operation functions for the C version of spinlock_t provided in `spinlock.rs`.
However, for newly developed features, please do not use the C version of `spinlock_t`, as it will be removed as code refactoring progresses.
:::
(_translated_label___spinlock_doc_spinlock_en)=
## 3. SpinLock - Spinlock with Guard
&emsp;&emsp;`SpinLock` is an encapsulation of `RawSpinLock`, enabling compile-time checks for issues such as "accessing critical section data without locking", "forgetting to unlock", and "double unlocking"; it also supports internal mutability of data.
&emsp;&emsp;Its struct prototype is as follows:
```rust
#[derive(Debug)]
pub struct SpinLock<T> {
lock: RawSpinlock,
/// 自旋锁保护的数据
data: UnsafeCell<T>,
}
```
### 3.1. Usage
&emsp;&emsp;You can initialize a SpinLock like this:
```rust
let x = SpinLock::new(Vec::new());
```
&emsp;&emsp;When initializing this SpinLock, you must pass the data you want to protect into the SpinLock, which will then manage it.
&emsp;&emsp;When you need to read or modify data protected by SpinLock, please first use the `lock()` method of SpinLock. This method will return a `SpinLockGuard`. You can use the member functions of the protected data to perform some operations, or directly read and write the protected data. (This is equivalent to obtaining a mutable reference to the protected data.)
&emsp;&emsp;The complete example is shown in the code below:
```rust
let x :SpinLock<Vec<i32>>= SpinLock::new(Vec::new());
{
let mut g :SpinLockGuard<Vec<i32>>= x.lock();
g.push(1);
g.push(2);
g.push(2);
assert!(g.as_slice() == [1, 2, 2] || g.as_slice() == [2, 2, 1]);
// 在此处SpinLock是加锁的状态
debug!("x={:?}", x);
}
// 由于上方的变量`g`也就是SpinLock守卫的生命周期结束自动释放了SpinLock。因此在此处SpinLock是放锁的状态
debug!("x={:?}", x);
```
&emsp;&emsp;For variables inside a struct, we can use SpinLock to perform fine-grained locking, that is, wrap the member variables that need to be locked in SpinLock, for example:
```rust
pub struct a {
pub data: SpinLock<data_struct>,
}
```
&emsp;&emsp;Of course, we can also lock the entire struct:
```rust
struct MyStruct {
pub data: data_struct,
}
/// 被全局加锁的结构体
pub struct LockedMyStruct(SpinLock<MyStruct>);
```
### 3.2. Principle
&emsp;&emsp;`SpinLock` can achieve compile-time checking because it introduces a `SpinLockGuard` as a guard. When writing code, we ensure that only after calling the `lock()` method of `SpinLock` to acquire the lock can a `SpinLockGuard` be generated. Moreover, whenever we want to access protected data, we must obtain a guard. We also implement the `Drop` trait for `SpinLockGuard`; when the guard's lifetime ends, the lock will be automatically released. There is no other way to release the lock. Therefore, we can know that, in a context, as long as the `SpinLockGuard`'s lifetime has not ended, it has the right to access the critical section data, and the data access is safe.
### 3.3. Existing Issues
#### 3.3.1. Double Locking
&emsp;&emsp;Please note that the compile-time checks supported by `SpinLock` are not omnipotent. It currently cannot detect the issue of "double locking" at compile time. Consider this scenario: function A acquires the lock, and then function B attempts to lock again, which results in a "double locking" issue. This kind of problem cannot be detected at compile time.
&emsp;&emsp;To address this issue, we recommend the following programming approach:
- If function B needs to access data within the critical section, function B should receive a parameter of type `&SpinLockGuard`, which is obtained by function A. In this way, function B can access the data within the critical section.