├── cpu-api ├── .gitignore ├── Makefile ├── Cargo.toml └── src │ ├── bin │ ├── p3.rs │ ├── p1.rs │ ├── p4.rs │ └── p2.rs │ └── main.rs ├── dist-intro ├── .gitignore ├── src │ ├── main.rs │ ├── transform.rs │ └── bin │ │ ├── server.rs │ │ └── client.rs ├── Makefile └── Cargo.toml ├── vm-intro ├── .gitignore ├── Makefile ├── Cargo.toml └── src │ └── bin │ └── va.rs ├── intro ├── src │ ├── lib.rs │ ├── main.rs │ ├── common.rs │ └── bin │ │ ├── cpu.rs │ │ ├── io.rs │ │ ├── mem.rs │ │ └── threads.rs └── Cargo.toml ├── threads-api ├── .gitignore ├── Cargo.toml ├── src │ └── bin │ │ ├── thread_create_simple_args.rs │ │ ├── thread_create.rs │ │ └── thread_create_with_return_args.rs └── Makefile ├── threads-bugs ├── .gitignore ├── Makefile ├── Cargo.toml └── src │ └── bin │ ├── ordering.rs │ ├── atomicity.rs │ ├── ordering_fixed.rs │ ├── atomicity_fixed.rs │ └── deadlock.rs ├── threads-locks ├── .gitignore ├── Makefile ├── Cargo.toml └── src │ └── bin │ └── compare-and-swap.rs ├── threads-sema ├── .gitignore ├── Cargo.toml ├── src │ └── bin │ │ ├── join.rs │ │ ├── binary.rs │ │ ├── zemaphore.rs │ │ ├── throttle.rs │ │ ├── dining_philosophers_deadlock.rs │ │ ├── dining_philosophers_no_deadlock.rs │ │ ├── producer_consumer_works.rs │ │ ├── dining_philosophers_deadlock_print.rs │ │ ├── dining_philosophers_no_deadlock_print.rs │ │ └── rwlock.rs └── Makefile ├── .gitignore ├── cpu-sched-lottery ├── src │ ├── main.rs │ └── bin │ │ └── lottery.rs ├── Makefile └── Cargo.toml ├── user-lib ├── Cargo.toml └── src │ └── lib.rs └── README.md /cpu-api/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /dist-intro/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /vm-intro/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /intro/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod common; 2 | -------------------------------------------------------------------------------- /threads-api/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /threads-bugs/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /threads-locks/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /threads-sema/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target 3 | tmpfile 4 | -------------------------------------------------------------------------------- /vm-intro/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cargo run --bin ${bin} 3 | -------------------------------------------------------------------------------- /threads-locks/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cargo run --bin ${bin} 3 | -------------------------------------------------------------------------------- /intro/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /cpu-sched-lottery/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /dist-intro/src/main.rs: -------------------------------------------------------------------------------- 1 | mod transform; 2 | fn main() { 3 | println!("Hello, world!"); 4 | } 5 | -------------------------------------------------------------------------------- /threads-bugs/Makefile: -------------------------------------------------------------------------------- 1 | # atomicity atomicity_fixed ordering ordering_fixed deadlock 2 | 3 | all: 4 | cargo run --bin ${bin} 5 | -------------------------------------------------------------------------------- /dist-intro/Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | clean: 4 | rm -f client server 5 | 6 | client: 7 | cargo run --bin client 8 | 9 | server: 10 | cargo run --bin server 11 | 12 | -------------------------------------------------------------------------------- /vm-intro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vm-intro" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /threads-api/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "threads-api" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /threads-locks/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "threads-locks" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /cpu-api/Makefile: -------------------------------------------------------------------------------- 1 | all: p1 p2 p3 p4 2 | 3 | clean: 4 | rm -f p1 p2 p3 p4 5 | 6 | p1: 7 | cargo run --bin p1 8 | 9 | p2: 10 | cargo run --bin p2 11 | 12 | p3: 13 | cargo run --bin p3 14 | 15 | p4: 16 | cargo run --bin p4 -------------------------------------------------------------------------------- /user-lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "user-lib" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | nix = "0.22.0" 10 | -------------------------------------------------------------------------------- /cpu-sched-lottery/Makefile: -------------------------------------------------------------------------------- 1 | all: p1 p2 p3 p4 2 | 3 | clean: 4 | rm -f p1 p2 p3 p4 5 | 6 | 1: 7 | cargo run --bin lottery 20 10 8 | 9 | p2: 10 | cargo run --bin p2 11 | 12 | p3: 13 | cargo run --bin p3 14 | 15 | p4: 16 | cargo run --bin p4 -------------------------------------------------------------------------------- /dist-intro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dist-intro" 3 | version = "0.1.0" 4 | authors = ["xushanpu123 <798304030@qq.com>"] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /cpu-api/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust" 3 | version = "0.1.0" 4 | authors = ["xushanpu123 <798304030@qq.com>"] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | nix = "0.22.0" 11 | libc ="0.2.0" -------------------------------------------------------------------------------- /intro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "intro" 3 | version = "0.1.0" 4 | authors = ["xushanpu123 <798304030@qq.com>"] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | libc = "0.2.0" 11 | nix = "0.22.0" -------------------------------------------------------------------------------- /cpu-sched-lottery/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cpu-sched-lottery" 3 | version = "0.1.0" 4 | authors = ["xushanpu123 <798304030@qq.com>"] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | rand = "0.8.0" -------------------------------------------------------------------------------- /threads-api/src/bin/thread_create_simple_args.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | 3 | fn mythread(args: i64) -> i64 { 4 | println!("{}", args); 5 | return args + 1; 6 | } 7 | 8 | fn main() { 9 | let handle = thread::spawn(|| mythread(100)); 10 | let rvalue = handle.join().unwrap(); 11 | println!("{}", rvalue); 12 | } 13 | -------------------------------------------------------------------------------- /threads-api/Makefile: -------------------------------------------------------------------------------- 1 | all: thread_create thread_create_simple_args thread_create_with_return_args 2 | 3 | thread_create: 4 | cargo run --bin thread_create 5 | 6 | thread_create_simple_args: 7 | cargo run --bin thread_create_simple_args 8 | 9 | thread_create_with_return_args: 10 | cargo run --bin thread_create_with_return_args 11 | -------------------------------------------------------------------------------- /threads-bugs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "threads-bugs" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | user-lib = { path = "../user-lib" } 10 | lazy_static = { version = "1.4", features = ["spin_no_std"] } 11 | -------------------------------------------------------------------------------- /threads-sema/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "threads-sema" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | std-semaphore = "0.1.0" 10 | user-lib = { path = "../user-lib" } 11 | lazy_static = { version = "1.4", features = ["spin_no_std"] } 12 | -------------------------------------------------------------------------------- /threads-api/src/bin/thread_create.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | 3 | #[derive(Debug)] 4 | struct myarg_t { 5 | a: i32, 6 | b: i32, 7 | } 8 | 9 | fn mythread(args: myarg_t) { 10 | println!("{:?}", args); 11 | } 12 | 13 | fn main() { 14 | let args = myarg_t { a: 10, b: 20 }; 15 | let handle = thread::spawn(|| mythread(args)); 16 | handle.join().unwrap(); 17 | } 18 | -------------------------------------------------------------------------------- /dist-intro/src/transform.rs: -------------------------------------------------------------------------------- 1 | pub fn u8_to_string(U8:&[u8])->String{ 2 | let mut res = String::new(); 3 | for i in U8{ 4 | res.push('a'+i); 5 | } 6 | res 7 | } 8 | 9 | pub fn string_to_u8(string:String)->&[u8]{ 10 | let mut U8 = [0;1000]; 11 | for i in 0..string.size(){ 12 | U8[i as usize] = string[i as usize]; 13 | } 14 | &U8[0..(string.size as usize)] 15 | } -------------------------------------------------------------------------------- /dist-intro/src/bin/server.rs: -------------------------------------------------------------------------------- 1 | use std::net::UdpSocket; 2 | fn main(){ 3 | let socket = UdpSocket::bind("0.0.0.0:10000").unwrap(); 4 | while true{ 5 | let mut message = [0;1000]; 6 | println!("server:: waiting..."); 7 | let rc = socket.recv_from(&mut message).unwrap().0; 8 | println!("server:: read message [size:{} contents:{}]\n", rc, std::str::from_utf8(&message).unwrap()) 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /vm-intro/src/bin/va.rs: -------------------------------------------------------------------------------- 1 | use std::alloc::{System,Layout,alloc}; 2 | use std::num::NonZeroUsize; 3 | fn main(){ 4 | 5 | println!("location of code : {}\n", main as usize); 6 | let layout = Layout::new::<[u8;10000]>(); 7 | let ptr = unsafe{alloc(layout)}; 8 | println!("location of heap : {}\n", ptr as usize); 9 | let x = 3; 10 | let ptr = &x as *const i32 as usize; 11 | println!("location of heap : {}\n", ptr); 12 | //int x = 3; 13 | //printf("location of stack: %p\n", &x); 14 | } -------------------------------------------------------------------------------- /threads-sema/src/bin/join.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::*; 2 | use std::thread; 3 | use std_semaphore::Semaphore; 4 | use user_lib::*; 5 | 6 | lazy_static! { 7 | static ref S: Semaphore = Semaphore::new(0); 8 | } 9 | 10 | fn child() { 11 | sleep(2); 12 | println!("child"); 13 | S.release(); // signal here: child is done 14 | } 15 | 16 | fn main() { 17 | println!("parent: begin"); 18 | thread::spawn(move || { 19 | child(); 20 | }); 21 | S.acquire(); 22 | 23 | println!("parent: end"); 24 | } 25 | -------------------------------------------------------------------------------- /dist-intro/src/bin/client.rs: -------------------------------------------------------------------------------- 1 | use std::net::UdpSocket; 2 | use std::str::from_utf8; 3 | fn main(){ 4 | 5 | let socket = UdpSocket::bind("0.0.0.0:20000").unwrap(); 6 | 7 | let message = "hello world".as_bytes(); 8 | println!("client:: send message [{}]",from_utf8(message).unwrap()); 9 | let rc = socket.send_to(&message, "0.0.0.0:10000").unwrap(); 10 | println!("client:: wait for reply...\n"); 11 | let mut message2 = [0;1000]; 12 | let rc = socket.recv_from(&mut message2).unwrap().0; 13 | println!("client:: got reply [size:{} contents:({})",rc,from_utf8(message).unwrap()); 14 | } 15 | -------------------------------------------------------------------------------- /threads-bugs/src/bin/ordering.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::*; 2 | use std::sync::Mutex; 3 | use std::thread; 4 | use user_lib::*; 5 | 6 | lazy_static!{ 7 | static ref mState:Mutex = Mutex::new(0); 8 | } 9 | 10 | fn mMain() { 11 | println!("mMain: begin\n"); 12 | let state = *mState.lock().unwrap(); 13 | println!("mMain: state is {}", state); 14 | } 15 | 16 | 17 | fn main() { 18 | println!("ordering: begin"); 19 | let mThread = thread::spawn(mMain); 20 | sleep(1); 21 | *mState.lock().unwrap() = 1; 22 | mThread.join().unwrap(); 23 | println!("ordering: end\n"); 24 | } 25 | -------------------------------------------------------------------------------- /threads-api/src/bin/thread_create_with_return_args.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | 3 | #[derive(Debug)] 4 | struct myarg_t { 5 | a: i32, 6 | b: i32, 7 | } 8 | 9 | #[derive(Debug)] 10 | struct myret_t { 11 | x: i32, 12 | y: i32, 13 | } 14 | 15 | fn mythread(args: myarg_t) -> myret_t { 16 | println!("{:?}", args); 17 | return myret_t { 18 | x: args.a, 19 | y: args.b, 20 | }; 21 | } 22 | 23 | fn main() { 24 | let args = myarg_t { a: 10, b: 20 }; 25 | let handle = thread::spawn(|| mythread(args)); 26 | let rvals = handle.join().unwrap(); 27 | println!("{:?}", rvals); 28 | } 29 | -------------------------------------------------------------------------------- /threads-sema/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cargo run --bin ${bin} 3 | 4 | rwlock: 5 | cargo run --bin rwlock 10000 10000 6 | 7 | producer_consumer_works: 8 | cargo run --bin producer_consumer_works 1000 100 10 9 | 10 | throttle: 11 | cargo run --bin throttle 1000 100 12 | 13 | dining_philosophers_no_deadlock: 14 | cargo run --bin dining_philosophers_no_deadlock 1000 15 | 16 | dining_philosophers_deadlock: 17 | cargo run --bin dining_philosophers_deadlock 1000 18 | 19 | dining_philosophers_no_deadlock_print: 20 | cargo run --bin dining_philosophers_no_deadlock_print 1000 21 | 22 | dining_philosophers_deadlock_print: 23 | cargo run --bin dining_philosophers_deadlock_print 1000 24 | -------------------------------------------------------------------------------- /intro/src/common.rs: -------------------------------------------------------------------------------- 1 | use std::time::{SystemTime}; 2 | pub fn spin(howlong: usize) { 3 | let earlier = SystemTime::now(); 4 | while SystemTime::now().duration_since(earlier).unwrap().as_secs() < howlong as u64 { 5 | continue; 6 | } 7 | } 8 | 9 | /*#ifndef __common_h__ 10 | #define __common_h__ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | double GetTime() { 17 | struct timeval t; 18 | int rc = gettimeofday(&t, NULL); 19 | assert(rc == 0); 20 | return (double) t.tv_sec + (double) t.tv_usec/1e6; 21 | } 22 | 23 | void Spin(int howlong) { 24 | double t = GetTime(); 25 | while ((GetTime() - t) < (double) howlong) 26 | ; // do nothing in loop 27 | } 28 | 29 | #endif // __common_h__*/ 30 | -------------------------------------------------------------------------------- /threads-sema/src/bin/binary.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::thread; 3 | use std_semaphore::Semaphore; 4 | 5 | static mut counter: i32 = 0; 6 | 7 | fn child(sema: Arc) { 8 | for i in 0..10000000 { 9 | sema.acquire(); 10 | unsafe { 11 | counter += 1; 12 | } 13 | sema.release(); 14 | } 15 | } 16 | 17 | fn main() { 18 | let mutex = Arc::new(Semaphore::new(1)); 19 | let mutex2 = mutex.clone(); 20 | let handle = thread::spawn(move || { 21 | child(mutex); 22 | }); 23 | let handle2 = thread::spawn(move || { 24 | child(mutex2); 25 | }); 26 | handle.join(); 27 | handle2.join(); 28 | unsafe { 29 | println!("result: {} (should be 20000000)", counter); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /intro/src/bin/cpu.rs: -------------------------------------------------------------------------------- 1 | use intro::common::spin; 2 | use std::env::args; 3 | use std::io::{self, Write}; 4 | 5 | fn main() -> std::io::Result<()> { 6 | let mut argv = args(); 7 | let argc = argv.len(); 8 | if argc != 2 { 9 | let mut stderr = io::stderr(); 10 | stderr.write(b"usage: cpu \n")?; 11 | } else { 12 | let argv1 = argv.nth(1).unwrap(); 13 | loop { 14 | println!("{}", argv1); 15 | spin(1); 16 | } 17 | } 18 | Ok(()) 19 | } 20 | 21 | /* 22 | #include 23 | #include 24 | #include "common.h" 25 | 26 | int main(int argc, char *argv[]) 27 | { 28 | if (argc != 2) { 29 | fprintf(stderr, "usage: cpu \n"); 30 | exit(1); 31 | } 32 | char *str = argv[1]; 33 | 34 | while (1) { 35 | printf("%s\n", str); 36 | Spin(1); 37 | } 38 | return 0; 39 | } 40 | */ 41 | -------------------------------------------------------------------------------- /user-lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub use nix::errno::Errno; 2 | pub use nix::sys::wait::{self, WaitStatus}; 3 | pub use nix::unistd::{ForkResult, Pid}; 4 | use std::convert::Infallible; 5 | use std::ffi::CStr; 6 | use std::time::SystemTime; 7 | 8 | pub fn fork() -> Result { 9 | unsafe { nix::unistd::fork() } 10 | } 11 | 12 | pub fn getpid() -> Pid { 13 | nix::unistd::getpid() 14 | } 15 | 16 | pub fn wait() -> Result { 17 | nix::sys::wait::wait() 18 | } 19 | 20 | pub fn sleep(seconds: u32) -> u32 { 21 | nix::unistd::sleep(seconds) 22 | } 23 | 24 | pub fn execvp>(filename: &CStr, args: &[S]) -> Result { 25 | nix::unistd::execvp(filename, args) 26 | } 27 | 28 | pub fn spin(howlong: usize) { 29 | let earlier = SystemTime::now(); 30 | while SystemTime::now().duration_since(earlier).unwrap().as_secs() < howlong as u64 {} 31 | } 32 | -------------------------------------------------------------------------------- /intro/src/bin/io.rs: -------------------------------------------------------------------------------- 1 | use std::fs::OpenOptions; 2 | use std::io::Write; 3 | 4 | fn main() { 5 | let mut f = OpenOptions::new() 6 | .truncate(true) 7 | .read(true) 8 | .create(true) 9 | .write(true) 10 | .open("./src/bin/tmpfile") 11 | .unwrap(); 12 | f.write_all(b"Hello, world\n").unwrap(); 13 | f.sync_all().unwrap(); 14 | } 15 | 16 | /* 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | int main(int argc, char *argv[]) { 26 | int fd = open("/tmp/file", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 27 | assert(fd >= 0); 28 | char buffer[20]; 29 | sprintf(buffer, "hello world\n"); 30 | int rc = write(fd, buffer, strlen(buffer)); 31 | assert(rc == (strlen(buffer))); 32 | fsync(fd); 33 | close(fd); 34 | return 0; 35 | } 36 | 37 | */ 38 | -------------------------------------------------------------------------------- /threads-bugs/src/bin/atomicity.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | use user_lib::*; 3 | 4 | #[derive(Debug)] 5 | struct thread_info_t { 6 | pid: i32, 7 | } 8 | 9 | static mut thd: Option = Some(thread_info_t { pid: 100 }); 10 | 11 | fn thread1() { 12 | println!("t1: before check"); 13 | unsafe { 14 | println!("t1: {:?}", thd); 15 | println!("t1: after check"); 16 | sleep(2); 17 | println!("t1: use!"); 18 | println!("t1: {:?}", thd); 19 | } 20 | } 21 | 22 | fn thread2() { 23 | println!(" t2: begin"); 24 | sleep(1); 25 | unsafe { 26 | println!(" t2: set to NULL"); 27 | thd = None; 28 | } 29 | } 30 | 31 | fn main() { 32 | println!("main: begin"); 33 | let handle1 = thread::spawn(|| thread1()); 34 | let handle2 = thread::spawn(|| thread2()); 35 | handle1.join().unwrap(); 36 | handle2.join().unwrap(); 37 | println!("main: end"); 38 | } 39 | -------------------------------------------------------------------------------- /threads-locks/src/bin/compare-and-swap.rs: -------------------------------------------------------------------------------- 1 | #![feature(llvm_asm)] 2 | static mut global:i32 = 0; 3 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 4 | fn compare_and_swap(ptr:*mut i32, old:i32, new:i32)->char { 5 | let mut ret:char = 'a'; 6 | unsafe { 7 | llvm_asm!(" lock\n" 8 | " cmpxchgl %2,%1\n" 9 | " sete %0\n" 10 | : "=q" (ret), "=m" (*ptr), 11 | : "r" (new), "m" (*ptr), "a" (old) 12 | : "memory" 13 | ); 14 | } 15 | ret 16 | } 17 | 18 | fn main() { 19 | unsafe{ 20 | println!("before successful cas: {}", global); 21 | let success = compare_and_swap(&global as *const i32 as *mut i32, 0, 100); 22 | println!("after successful cas: {} (success: {})\n", global, success); 23 | 24 | println!("before failing cas: {}\n", global); 25 | success = compare_and_swap(&global as *const i32 as *mut i32, 0, 200); 26 | println!("after failing cas: {} (old: {})\n", global, success); 27 | } 28 | } -------------------------------------------------------------------------------- /threads-bugs/src/bin/ordering_fixed.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::*; 2 | use std::mem::drop; 3 | use std::sync::{Arc, Condvar, Mutex}; 4 | use std::thread; 5 | use user_lib::*; 6 | 7 | lazy_static!{ 8 | static ref mState:Mutex = Mutex::new(0); 9 | } 10 | 11 | fn main() { 12 | let pair = Arc::new((Mutex::new(false), Condvar::new())); 13 | let pair2 = Arc::clone(&pair); 14 | println!("ordering: begin"); 15 | let handle = thread::spawn(move || { 16 | let (lock, cvar) = &*pair; 17 | let mut started = lock.lock().unwrap(); 18 | while !*started { 19 | started = cvar.wait(started).unwrap(); 20 | } 21 | println!("mMain: state is {}", *mState.lock().unwrap()); 22 | }); 23 | sleep(1); 24 | let (lock, cvar) = &*pair2; 25 | let mut started = lock.lock().unwrap(); 26 | *mState.lock().unwrap() = 1; 27 | *started = true; 28 | cvar.notify_one(); 29 | drop(started); // unlock 30 | handle.join().unwrap(); 31 | println!("ordering: end"); 32 | } 33 | -------------------------------------------------------------------------------- /threads-sema/src/bin/zemaphore.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Arc, Condvar, Mutex}; 2 | use std::thread; 3 | use user_lib::*; 4 | 5 | struct Zem { 6 | cond: Condvar, 7 | lock: Mutex, 8 | } 9 | 10 | impl Zem { 11 | pub fn new(value: i32) -> Self { 12 | Zem { 13 | cond: Condvar::new(), 14 | lock: Mutex::new(value), 15 | } 16 | } 17 | 18 | pub fn wait(&self) { 19 | let mut lock = self.lock.lock().unwrap(); 20 | while *lock <= 0 { 21 | lock = self.cond.wait(lock).unwrap(); 22 | } 23 | *lock -= 1; 24 | } 25 | 26 | pub fn post(&self) { 27 | let mut lock = self.lock.lock().unwrap(); 28 | *lock += 1; 29 | self.cond.notify_one(); 30 | } 31 | } 32 | 33 | fn main() { 34 | let s = Arc::new(Zem::new(0)); 35 | let s1 = s.clone(); 36 | println!("parent: begin"); 37 | thread::spawn(move || { 38 | sleep(4); 39 | println!("child"); 40 | s1.post(); 41 | }); 42 | s.wait(); 43 | println!("parent: end"); 44 | } 45 | -------------------------------------------------------------------------------- /threads-bugs/src/bin/atomicity_fixed.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::*; 2 | use std::sync::Mutex; 3 | use std::thread; 4 | use user_lib::*; 5 | 6 | #[derive(Debug)] 7 | struct thread_info_t { 8 | pid: i32, 9 | } 10 | 11 | lazy_static! { 12 | static ref thd: Mutex> = Mutex::new(Some(thread_info_t { pid: 100 })); 13 | } 14 | 15 | fn thread1() { 16 | println!("t1: before check"); 17 | let thd_lock = thd.lock().unwrap(); 18 | println!("t1: {:?}", *thd_lock); 19 | println!("t1: after check"); 20 | sleep(2); 21 | println!("t1: use!"); 22 | println!("t1: {:?}", *thd_lock); 23 | } 24 | 25 | fn thread2() { 26 | println!(" t2: begin"); 27 | sleep(1); 28 | let mut thd_lock = thd.lock(); 29 | println!(" t2: set to NULL"); 30 | *thd_lock.unwrap() = None; 31 | } 32 | 33 | fn main() { 34 | println!("main: begin"); 35 | let handle1 = thread::spawn(|| thread1()); 36 | let handle2 = thread::spawn(|| thread2()); 37 | handle1.join().unwrap(); 38 | handle2.join().unwrap(); 39 | println!("main: end"); 40 | } 41 | -------------------------------------------------------------------------------- /cpu-api/src/bin/p3.rs: -------------------------------------------------------------------------------- 1 | extern crate nix; 2 | extern crate libc; 3 | use nix::{unistd::*,sys::wait::*}; 4 | use std::ptr::null; 5 | use std::ffi::CStr; 6 | fn main() 7 | { 8 | println!("hello world (pid:{})", getpid()); 9 | match unsafe{fork()} { 10 | Ok(ForkResult::Parent { child, .. }) => { 11 | if let Ok(wc) = wait(){ 12 | if let WaitStatus::Exited(pid,exitcode) = wc{ 13 | println!("hello, I am parent of {}(wc:{}) (pid:{})", child, pid,getpid()); 14 | } 15 | } 16 | } 17 | Ok(ForkResult::Child) => { 18 | println!("hello, I am child (pid:{})",getpid()); 19 | let arg0 = CStr::from_bytes_with_nul(b"wc\0").unwrap(); 20 | let arg1 = CStr::from_bytes_with_nul(b"p3.rs\0").unwrap(); 21 | let arg2 = CStr::from_bytes_with_nul(b"\0").unwrap(); 22 | let myargs:[&CStr;3]=[&arg0,&arg1,&arg2]; 23 | execvp(myargs[0],&myargs); 24 | sleep(1); 25 | } 26 | Err(_) => { 27 | println!("Fork failed"); 28 | std::process::exit(1); 29 | } 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Intro 2 | 3 | 此项目为`ostep code`的Rust版本,其C语言版本的代码地址为: 4 | 5 | https://github.com/remzi-arpacidusseau/ostep-code 6 | 7 | 其主要内容介绍如下:(每个目录包含一个主题/章节,例子写在src/bin目录下,通过cargo run --bin *appname* 来运行) 8 | 9 | - cpu-api 10 | 11 | 展示fork(),execv(),sleep(),wait()等与进程相关基本函数的功能。 12 | 13 | - cpu-sched-lottery 14 | 15 | rust实现了链表linklist和模拟了一个基础的随机调度。 16 | 17 | 18 | - dist-intro 19 | 20 | 展示一个基础的客户端、服务端通过UDP通信的功能。 21 | 22 | - intro 23 | 24 | 展示进程、I/O、多线程、内存分配的相关功能。 25 | 26 | - threads-api 27 | 28 | 展示进程的创建和阻塞等功能。 29 | 30 | 31 | - threads-bugs 32 | 33 | 通过特定的程序来触发进程的死锁、读写不同步、不支持互斥等BUG。 34 | 35 | - threads-cv 36 | 37 | 利用锁和条件变量来实现一些基础的同步互斥功能。 38 | 39 | 40 | 41 | - threads-intro 42 | 43 | 通过多线程追踪变量的变化来分析多线程并行执行的特点。 44 | 45 | 46 | 47 | - threads-sema 48 | 49 | 用信号量来解决读写问题、哲学家就餐问题、生产者消费问题、基本同步问题 50 | 51 | 52 | 53 | - vm-intro 54 | 55 | 展示代码段数据(函数指针)、栈数据(局部变量)、堆上数据(alloc的数据)的地址。 56 | 57 | 58 | - threads-locks/compare-and-swap(未实现) 59 | 60 | 实现一个基本的lock功能通过compare&swap原语。 61 | 62 | 63 | ## Developers 64 | 65 | Xu Shanpu, Liu Fengyuan, Chen Yu -------------------------------------------------------------------------------- /cpu-api/src/bin/p1.rs: -------------------------------------------------------------------------------- 1 | extern crate nix; 2 | use nix::unistd::*; 3 | //mod cpu_api; 4 | /*int 5 | main(int argc, char *argv[]) 6 | { 7 | printf("hello world (pid:%d)\n", (int) getpid()); 8 | int rc = fork(); 9 | if (rc < 0) { 10 | // fork failed; exit 11 | fprintf(stderr, "fork failed\n"); 12 | exit(1); 13 | } else if (rc == 0) { 14 | // child (new process) 15 | printf("hello, I am child (pid:%d)\n", (int) getpid()); 16 | } else { 17 | // parent goes down this path (original process) 18 | printf("hello, I am parent of %d (pid:%d)\n", 19 | rc, (int) getpid()); 20 | } 21 | return 0; 22 | }*/ 23 | fn main(){ 24 | println!("hello world (pid:{})",getpid()); 25 | match unsafe{fork()} { 26 | Ok(ForkResult::Parent { child, .. }) => { 27 | println!("hello, I am parent of {} (pid:{})", child, getpid()); 28 | } 29 | Ok(ForkResult::Child) => println!("hello, I am child (pid:{})",getpid()), 30 | Err(_) => { 31 | println!("Fork failed"); 32 | std::process::exit(1); 33 | } 34 | } 35 | 36 | 37 | 38 | } -------------------------------------------------------------------------------- /cpu-api/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate nix; 2 | use nix::unistd::*; 3 | //mod cpu_api; 4 | /*int 5 | main(int argc, char *argv[]) 6 | { 7 | printf("hello world (pid:%d)\n", (int) getpid()); 8 | int rc = fork(); 9 | if (rc < 0) { 10 | // fork failed; exit 11 | fprintf(stderr, "fork failed\n"); 12 | exit(1); 13 | } else if (rc == 0) { 14 | // child (new process) 15 | printf("hello, I am child (pid:%d)\n", (int) getpid()); 16 | } else { 17 | // parent goes down this path (original process) 18 | printf("hello, I am parent of %d (pid:%d)\n", 19 | rc, (int) getpid()); 20 | } 21 | return 0; 22 | }*/ 23 | fn main(){ 24 | println!("hello world (pid:{})",getpid()); 25 | match unsafe{fork()} { 26 | Ok(ForkResult::Parent { child, .. }) => { 27 | println!("hello, I am parent of {} (pid:{})", child, getpid()); 28 | } 29 | Ok(ForkResult::Child) => println!("hello, I am child (pid:{})",getpid()), 30 | Err(_) => { 31 | println!("Fork failed"); 32 | std::process::exit(1); 33 | } 34 | } 35 | 36 | 37 | 38 | } -------------------------------------------------------------------------------- /cpu-api/src/bin/p4.rs: -------------------------------------------------------------------------------- 1 | use gag::Redirect; 2 | use std::ffi::CStr; 3 | use std::fs::OpenOptions; 4 | use user_lib::*; 5 | 6 | fn main() { 7 | match fork() { 8 | Ok(ForkResult::Parent { child: _, .. }) => { 9 | if let Ok(wc) = wait() { 10 | if let WaitStatus::Exited(pid, _exitcode) = wc { 11 | assert!(pid.as_raw() >= 0); 12 | } 13 | } 14 | } 15 | Ok(ForkResult::Child) => { 16 | let log = OpenOptions::new() 17 | .truncate(true) 18 | .read(true) 19 | .create(true) 20 | .write(true) 21 | .open("./p4.output") 22 | .unwrap(); 23 | let _print_redirect = Redirect::stdout(log).unwrap(); 24 | let arg0 = CStr::from_bytes_with_nul(b"wc\0").unwrap(); 25 | let arg1 = CStr::from_bytes_with_nul(b"p4.rs\0").unwrap(); 26 | let myargs: [&CStr; 2] = [&arg0, &arg1]; 27 | execvp(myargs[0], &myargs).unwrap(); 28 | } 29 | Err(_) => { 30 | println!("Fork failed"); 31 | std::process::exit(1); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /cpu-api/src/bin/p2.rs: -------------------------------------------------------------------------------- 1 | extern crate nix; 2 | use nix::{unistd::*,sys::wait::*}; 3 | use std::ptr::null; 4 | fn main() 5 | { 6 | println!("hello world (pid:{})", getpid()); 7 | match unsafe{fork()} { 8 | Ok(ForkResult::Parent { child, .. }) => { 9 | if let Ok(wc) = wait(){ 10 | if let WaitStatus::Exited(pid,exitcode) = wc{ 11 | println!("hello, I am parent of {}(wc:{}) (pid:{})", child, pid,getpid()); 12 | } 13 | } 14 | } 15 | Ok(ForkResult::Child) => { 16 | println!("hello, I am child (pid:{})",getpid()); 17 | sleep(1); 18 | } 19 | Err(_) => { 20 | println!("Fork failed"); 21 | std::process::exit(1); 22 | } 23 | } 24 | /*int rc = fork(); 25 | if (rc < 0) { 26 | // fork failed; exit 27 | fprintf(stderr, "fork failed\n"); 28 | exit(1); 29 | } else if (rc == 0) { 30 | // child (new process) 31 | printf("hello, I am child (pid:%d)\n", (int) getpid()); 32 | sleep(1); 33 | } else { 34 | // parent goes down this path (original process) 35 | int wc = wait(NULL); 36 | printf("hello, I am parent of %d (wc:%d) (pid:%d)\n", 37 | rc, wc, (int) getpid()); 38 | } 39 | return 0;*/ 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /threads-sema/src/bin/throttle.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::*; 2 | use std::env::args; 3 | use std::io::{self, Write}; 4 | use std::process::*; 5 | use std::sync::Arc; 6 | use std::thread; 7 | use std_semaphore::Semaphore; 8 | use user_lib::*; 9 | 10 | lazy_static! { 11 | static ref SEM: Arc = Arc::new(Semaphore::new(0)); 12 | } 13 | 14 | fn main() { 15 | let argv = args(); 16 | let argc = argv.len(); 17 | if argc != 3 { 18 | let mut stderr = io::stderr(); 19 | stderr 20 | .write(b"usage: throttle \n") 21 | .unwrap(); 22 | exit(1); 23 | } 24 | let num_threads = args().nth(1).unwrap().parse::().unwrap(); 25 | let sem_value = args().nth(2).unwrap().parse::().unwrap(); 26 | for _ in 0..sem_value { 27 | SEM.release(); 28 | } 29 | 30 | println!("parent: begin"); 31 | let mut consumer_handle = Vec::new(); 32 | for i in 0..num_threads { 33 | let handle = thread::spawn(move || { 34 | // child 35 | SEM.acquire(); 36 | println!("child {}", i); 37 | sleep(1); 38 | SEM.release(); 39 | }); 40 | consumer_handle.push(handle); 41 | } 42 | for handle in consumer_handle { 43 | handle.join().unwrap(); 44 | } 45 | println!("parent: end"); 46 | } 47 | -------------------------------------------------------------------------------- /threads-bugs/src/bin/deadlock.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::*; 2 | use std::mem::drop; 3 | use std::sync::Mutex; 4 | use std::thread; 5 | use user_lib::*; 6 | 7 | lazy_static!{ 8 | static ref L1:Mutex = Mutex::new(1); 9 | static ref L2:Mutex = Mutex::new(1); 10 | } 11 | fn thread1(){ 12 | println!("t1: begin"); 13 | println!("t1: try to acquire L1..."); 14 | let l1 = L1.lock().unwrap(); 15 | sleep(1); 16 | println!("t1: L1 acquired"); 17 | println!("t1: try to acquire L2..."); 18 | let l2 = L2.lock().unwrap(); 19 | println!("t1: L2 acquired"); 20 | drop(l1); 21 | drop(l2); 22 | } 23 | fn thread2(){ 24 | println!(" t2: begin"); 25 | println!(" t2: try to acquire L2..."); 26 | let l2 = L2.lock().unwrap(); 27 | println!(" t2: L2 acquired"); 28 | println!(" t2: try to acquire L1.."); 29 | let l1 = L1.lock().unwrap(); 30 | println!(" t2: L1 acquired"); 31 | drop(l1); 32 | drop(l2); 33 | } 34 | fn main(){ 35 | println!("main: begin"); 36 | let p1 = thread::spawn(||{ 37 | thread1(); 38 | }); 39 | let p2 = thread::spawn(||{ 40 | thread2(); 41 | }); 42 | p1.join().unwrap(); 43 | p2.join().unwrap(); 44 | println!("main: end"); 45 | 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /threads-sema/src/bin/dining_philosophers_deadlock.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::*; 2 | use std::env::args; 3 | use std::io::{self, Write}; 4 | use std::thread; 5 | use std_semaphore::Semaphore; 6 | 7 | lazy_static! { 8 | static ref FORKS: Vec = vec![ 9 | Semaphore::new(1), 10 | Semaphore::new(1), 11 | Semaphore::new(1), 12 | Semaphore::new(1), 13 | Semaphore::new(1) 14 | ]; 15 | } 16 | 17 | fn think() {} 18 | 19 | fn eat() {} 20 | 21 | fn left(i: i32) -> usize { 22 | i as usize 23 | } 24 | 25 | fn right(i: i32) -> usize { 26 | ((i + 1) % 5) as usize 27 | } 28 | 29 | fn get_forks(i: i32) { 30 | FORKS[left(i)].acquire(); 31 | FORKS[right(i)].acquire(); 32 | } 33 | 34 | fn put_forks(i: i32) { 35 | FORKS[right(i)].release(); 36 | FORKS[left(i)].release(); 37 | } 38 | 39 | fn philosopher(id: i32, num_loops: i32) { 40 | for _ in 0..num_loops { 41 | think(); 42 | get_forks(id); 43 | eat(); 44 | put_forks(id); 45 | } 46 | } 47 | 48 | fn main() { 49 | let argv = args(); 50 | let argc = argv.len(); 51 | if argc != 2 { 52 | let mut stderr = io::stderr(); 53 | stderr 54 | .write(b"usage: dining_philosophers \n") 55 | .unwrap(); 56 | std::process::exit(1); 57 | } 58 | let num_loops = args().nth(1).unwrap().parse::().unwrap(); 59 | println!("dining: started"); 60 | 61 | let mut handles = Vec::new(); 62 | for i in 0..5 { 63 | handles.push(thread::spawn(move || philosopher(i as i32, num_loops))); 64 | } 65 | for handle in handles { 66 | handle.join().unwrap(); 67 | } 68 | 69 | println!("dining: finished"); 70 | } 71 | -------------------------------------------------------------------------------- /intro/src/bin/mem.rs: -------------------------------------------------------------------------------- 1 | extern crate nix; 2 | use intro::common::spin; 3 | use nix::unistd::{getppid}; 4 | use std::alloc::{alloc, Layout}; 5 | use std::env::args; 6 | use std::io::{self, Write}; 7 | fn main() -> std::io::Result<()> { 8 | let argv = args(); 9 | let argc = argv.len(); 10 | if argc != 2 { 11 | let mut stderr = io::stderr(); 12 | stderr.write(b"usage: mem \n")?; 13 | std::process::exit(1); 14 | } else { 15 | let layout = Layout::new::(); 16 | let p = unsafe { alloc(layout) }; 17 | //assert_ne!(p,std::ptr::null()); 18 | println!( 19 | "({}) addr pointed to by p: 0x{:x}\n", 20 | getppid().as_raw(), 21 | p as usize 22 | ); 23 | unsafe { 24 | // assign value to addr stored in p 25 | *(p as *mut i32) = args().nth(1).unwrap().parse::().unwrap(); 26 | } 27 | loop { 28 | spin(1); 29 | unsafe { 30 | *(p as *mut i32) = *(p as *mut i32) + 1; 31 | } 32 | println!("({}) value of p: 0x{:x}\n", getppid().as_raw(), unsafe { 33 | *(p as *mut i32) 34 | }); 35 | } 36 | } 37 | } 38 | 39 | /* 40 | #include 41 | #include 42 | #include 43 | #include "common.h" 44 | 45 | int main(int argc, char *argv[]) { 46 | if (argc != 2) { 47 | fprintf(stderr, "usage: mem \n"); 48 | exit(1); 49 | } 50 | int *p; 51 | p = malloc(sizeof(int)); 52 | assert(p != NULL); 53 | printf("(%d) addr pointed to by p: %p\n", (int) getpid(), p); 54 | *p = atoi(argv[1]); // assign value to addr stored in p 55 | while (1) { 56 | Spin(1); 57 | *p = *p + 1; 58 | printf("(%d) value of p: %d\n", getpid(), *p); 59 | } 60 | return 0; 61 | } 62 | */ 63 | -------------------------------------------------------------------------------- /threads-sema/src/bin/dining_philosophers_no_deadlock.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::*; 2 | use std::env::args; 3 | use std::io::{self, Write}; 4 | use std::thread; 5 | use std_semaphore::Semaphore; 6 | 7 | lazy_static! { 8 | static ref FORKS: Vec = vec![ 9 | Semaphore::new(1), 10 | Semaphore::new(1), 11 | Semaphore::new(1), 12 | Semaphore::new(1), 13 | Semaphore::new(1) 14 | ]; 15 | } 16 | 17 | fn think() {} 18 | 19 | fn eat() {} 20 | 21 | fn left(i: i32) -> usize { 22 | i as usize 23 | } 24 | 25 | fn right(i: i32) -> usize { 26 | ((i + 1) % 5) as usize 27 | } 28 | 29 | fn get_forks(i: i32) { 30 | if i == 4 { 31 | FORKS[right(i)].acquire(); 32 | FORKS[left(i)].acquire(); 33 | } else { 34 | FORKS[left(i)].acquire(); 35 | FORKS[right(i)].acquire(); 36 | } 37 | } 38 | 39 | fn put_forks(i: i32) { 40 | FORKS[right(i)].release(); 41 | FORKS[left(i)].release(); 42 | } 43 | 44 | fn philosopher(id: i32, num_loops: i32) { 45 | for _ in 0..num_loops { 46 | think(); 47 | get_forks(id); 48 | eat(); 49 | put_forks(id); 50 | } 51 | } 52 | 53 | fn main() { 54 | let argv = args(); 55 | let argc = argv.len(); 56 | if argc != 2 { 57 | let mut stderr = io::stderr(); 58 | stderr 59 | .write(b"usage: dining_philosophers \n") 60 | .unwrap(); 61 | std::process::exit(1); 62 | } 63 | let num_loops = args().nth(1).unwrap().parse::().unwrap(); 64 | println!("dining: started"); 65 | 66 | let mut handles = Vec::new(); 67 | for i in 0..5 { 68 | handles.push(thread::spawn(move || philosopher(i as i32, num_loops))); 69 | } 70 | for handle in handles { 71 | handle.join().unwrap(); 72 | } 73 | 74 | println!("dining: finished"); 75 | } 76 | -------------------------------------------------------------------------------- /intro/src/bin/threads.rs: -------------------------------------------------------------------------------- 1 | extern crate nix; 2 | use libc::c_void; 3 | use libc::{pthread_create, pthread_join, pthread_t}; 4 | use std::env::args; 5 | use std::io::{self, Write}; 6 | static mut COUNTER: i32 = 0; 7 | static mut LOOPS: i32 = 0; 8 | pub extern "C" fn worker(_args: *mut c_void) -> *mut c_void { 9 | unsafe { 10 | for _i in 0..LOOPS { 11 | COUNTER = COUNTER + 1; 12 | } 13 | } 14 | 0 as *mut c_void 15 | } 16 | fn main() -> std::io::Result<()> { 17 | let mut argv = args(); 18 | let argc = argv.len(); 19 | if argc != 2 { 20 | let mut stderr = io::stderr(); 21 | stderr.write(b"usage: threads \n")?; 22 | } else { 23 | unsafe { 24 | LOOPS = argv.nth(1).unwrap().parse::().unwrap(); 25 | } 26 | let mut p1: pthread_t = 0; 27 | let mut p2: pthread_t = 0; 28 | unsafe { 29 | println!("Initial value : {}\n", COUNTER); 30 | } 31 | unsafe { 32 | pthread_create(&mut p1, std::ptr::null(), worker, 0 as *mut c_void); 33 | pthread_create(&mut p2, std::ptr::null(), worker, 0 as *mut c_void); 34 | pthread_join(p1, 0 as *mut *mut c_void); 35 | pthread_join(p2, 0 as *mut *mut c_void); 36 | } 37 | unsafe { 38 | println!("Final value : {}\n", COUNTER); 39 | } 40 | } 41 | Ok(()) 42 | } 43 | 44 | /* 45 | #include 46 | #include 47 | #include "common.h" 48 | #include "common_threads.h" 49 | 50 | volatile int counter = 0; 51 | int loops; 52 | 53 | void *worker(void *arg) { 54 | int i; 55 | for (i = 0; i < loops; i++) { 56 | counter++; 57 | } 58 | return NULL; 59 | } 60 | 61 | int main(int argc, char *argv[]) { 62 | if (argc != 2) { 63 | fprintf(stderr, "usage: threads \n"); 64 | exit(1); 65 | } 66 | loops = atoi(argv[1]); 67 | pthread_t p1, p2; 68 | printf("Initial value : %d\n", counter); 69 | Pthread_create(&p1, NULL, worker, NULL); 70 | Pthread_create(&p2, NULL, worker, NULL); 71 | Pthread_join(p1, NULL); 72 | Pthread_join(p2, NULL); 73 | printf("Final value : %d\n", counter); 74 | return 0; 75 | } 76 | */ 77 | -------------------------------------------------------------------------------- /threads-sema/src/bin/producer_consumer_works.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::*; 2 | use std::collections::VecDeque; 3 | use std::env::args; 4 | use std::io::{self, Write}; 5 | use std::process::exit; 6 | use std::sync::Mutex; 7 | use std::thread; 8 | use std_semaphore::Semaphore; 9 | 10 | lazy_static! { 11 | static ref BUFFER: Mutex> = Mutex::new(VecDeque::new()); 12 | static ref EMPTY: Semaphore = Semaphore::new(0); 13 | static ref FILL: Semaphore = Semaphore::new(0); 14 | } 15 | 16 | fn main() { 17 | let argv = args(); 18 | let argc = argv.len(); 19 | if argc != 4 { 20 | let mut stderr = io::stderr(); 21 | stderr.write(b"usage: cpu \n").unwrap(); 22 | exit(1); 23 | } 24 | let max = args().nth(1).unwrap().parse::().unwrap(); 25 | let loops = args().nth(2).unwrap().parse::().unwrap(); 26 | let consumers = args().nth(3).unwrap().parse::().unwrap(); 27 | for _ in 0..max { 28 | EMPTY.release(); 29 | } 30 | 31 | let producer_handle = thread::spawn(move || { 32 | for i in 0..loops { 33 | EMPTY.acquire(); 34 | let mut buffer2 = BUFFER.lock().unwrap(); 35 | buffer2.push_back(i); // do_fill 36 | FILL.release(); 37 | } 38 | 39 | // end case: put an end-of-production marker (-1) 40 | // into shared BUFFER, one per consumer 41 | for _ in 0..consumers { 42 | EMPTY.acquire(); 43 | let mut buffer2 = BUFFER.lock().unwrap(); 44 | buffer2.push_back(-1); // do_fill 45 | FILL.release(); 46 | } 47 | }); 48 | let mut consumer_handle = VecDeque::new(); 49 | for _ in 0..consumers { 50 | let handle = thread::spawn(move || { 51 | let mut tmp = 0; 52 | while tmp != -1 { 53 | FILL.acquire(); 54 | let mut buffer2 = BUFFER.lock().unwrap(); 55 | tmp = buffer2.pop_front().unwrap(); // do get 56 | EMPTY.release(); 57 | } 58 | }); 59 | consumer_handle.push_back(handle); 60 | } 61 | producer_handle.join().unwrap(); 62 | for handle in consumer_handle { 63 | handle.join().unwrap(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /threads-sema/src/bin/dining_philosophers_deadlock_print.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::*; 2 | use std::env::args; 3 | use std::io::{self, Write}; 4 | use std::sync::Mutex; 5 | use std::thread; 6 | use std_semaphore::Semaphore; 7 | 8 | lazy_static! { 9 | static ref FORKS: Vec = vec![ 10 | Semaphore::new(1), 11 | Semaphore::new(1), 12 | Semaphore::new(1), 13 | Semaphore::new(1), 14 | Semaphore::new(1) 15 | ]; 16 | static ref PRINT_LOCK: Mutex = Mutex::new(true); 17 | } 18 | 19 | fn lock_print(s: String, space: i32) { 20 | let _lock = PRINT_LOCK.lock().unwrap(); 21 | for _ in 0..space * 10 { 22 | print!(" "); 23 | } 24 | println!("{}", s); 25 | } 26 | 27 | fn think() {} 28 | 29 | fn eat() {} 30 | 31 | fn left(i: i32) -> usize { 32 | i as usize 33 | } 34 | 35 | fn right(i: i32) -> usize { 36 | ((i + 1) % 5) as usize 37 | } 38 | 39 | fn get_forks(i: i32) { 40 | lock_print(format!("{}: try {}", i, left(i)), i); 41 | FORKS[left(i)].acquire(); 42 | lock_print(format!("{}: try {}", i, right(i)), i); 43 | FORKS[right(i)].acquire(); 44 | } 45 | 46 | fn put_forks(i: i32) { 47 | FORKS[right(i)].release(); 48 | FORKS[left(i)].release(); 49 | } 50 | 51 | fn philosopher(id: i32, num_loops: i32) { 52 | lock_print(format!("{}: start", id), id); 53 | for _ in 0..num_loops { 54 | lock_print(format!("{}: think", id), id); 55 | think(); 56 | get_forks(id); 57 | lock_print(format!("{}: eat", id), id); 58 | eat(); 59 | put_forks(id); 60 | } 61 | } 62 | 63 | fn main() { 64 | let argv = args(); 65 | let argc = argv.len(); 66 | if argc != 2 { 67 | let mut stderr = io::stderr(); 68 | stderr 69 | .write(b"usage: dining_philosophers \n") 70 | .unwrap(); 71 | std::process::exit(1); 72 | } 73 | let num_loops = args().nth(1).unwrap().parse::().unwrap(); 74 | println!("dining: started"); 75 | 76 | let mut handles = Vec::new(); 77 | for i in 0..5 { 78 | handles.push(thread::spawn(move || philosopher(i as i32, num_loops))); 79 | } 80 | for handle in handles { 81 | handle.join().unwrap(); 82 | } 83 | 84 | println!("dining: finished"); 85 | } 86 | -------------------------------------------------------------------------------- /threads-sema/src/bin/dining_philosophers_no_deadlock_print.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::*; 2 | use std::env::args; 3 | use std::io::{self, Write}; 4 | use std::sync::Mutex; 5 | use std::thread; 6 | use std_semaphore::Semaphore; 7 | 8 | lazy_static! { 9 | static ref FORKS: Vec = vec![ 10 | Semaphore::new(1), 11 | Semaphore::new(1), 12 | Semaphore::new(1), 13 | Semaphore::new(1), 14 | Semaphore::new(1) 15 | ]; 16 | static ref PRINT_LOCK: Mutex = Mutex::new(true); 17 | } 18 | 19 | fn lock_print(s: String, space: i32) { 20 | let _lock = PRINT_LOCK.lock().unwrap(); 21 | for _ in 0..space * 10 { 22 | print!(" "); 23 | } 24 | println!("{}", s); 25 | } 26 | 27 | fn think() {} 28 | 29 | fn eat() {} 30 | 31 | fn left(i: i32) -> usize { 32 | i as usize 33 | } 34 | 35 | fn right(i: i32) -> usize { 36 | ((i + 1) % 5) as usize 37 | } 38 | 39 | fn get_forks(i: i32) { 40 | if i == 4 { 41 | lock_print(format!("4: try {}", right(i)), i); 42 | FORKS[right(i)].acquire(); 43 | lock_print(format!("4: try {}", left(i)), i); 44 | FORKS[left(i)].acquire(); 45 | } else { 46 | lock_print(format!("{}: try {}", i, left(i)), i); 47 | FORKS[left(i)].acquire(); 48 | lock_print(format!("{}: try {}", i, right(i)), i); 49 | FORKS[right(i)].acquire(); 50 | } 51 | } 52 | 53 | fn put_forks(i: i32) { 54 | FORKS[right(i)].release(); 55 | FORKS[left(i)].release(); 56 | } 57 | 58 | fn philosopher(id: i32, num_loops: i32) { 59 | lock_print(format!("{}: start", id), id); 60 | for _ in 0..num_loops { 61 | lock_print(format!("{}: think", id), id); 62 | think(); 63 | get_forks(id); 64 | lock_print(format!("{}: eat", id), id); 65 | eat(); 66 | put_forks(id); 67 | } 68 | } 69 | 70 | fn main() { 71 | let argv = args(); 72 | let argc = argv.len(); 73 | if argc != 2 { 74 | let mut stderr = io::stderr(); 75 | stderr 76 | .write(b"usage: dining_philosophers \n") 77 | .unwrap(); 78 | std::process::exit(1); 79 | } 80 | let num_loops = args().nth(1).unwrap().parse::().unwrap(); 81 | println!("dining: started"); 82 | 83 | let mut handles = Vec::new(); 84 | for i in 0..5 { 85 | handles.push(thread::spawn(move || philosopher(i as i32, num_loops))); 86 | } 87 | for handle in handles { 88 | handle.join().unwrap(); 89 | } 90 | 91 | println!("dining: finished"); 92 | } 93 | -------------------------------------------------------------------------------- /threads-sema/src/bin/rwlock.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::*; 2 | use std::env::args; 3 | use std::io::{self, Write}; 4 | use std::sync::Mutex; 5 | use std::thread; 6 | use std_semaphore::Semaphore; 7 | 8 | static mut COUNTER: i32 = 0; 9 | 10 | lazy_static! { 11 | static ref LOCK: Mutex = Mutex::new(Rwlock::new()); 12 | } 13 | 14 | struct Rwlock { 15 | writelock: Semaphore, 16 | lock: Semaphore, 17 | readers: i32, 18 | } 19 | 20 | impl Rwlock { 21 | pub fn new() -> Self { 22 | Rwlock { 23 | writelock: Semaphore::new(1), 24 | lock: Semaphore::new(1), 25 | readers: 0, 26 | } 27 | } 28 | 29 | pub fn acquire_readlock(&mut self) { 30 | self.lock.acquire(); 31 | self.readers += 1; 32 | if self.readers == 1 { 33 | self.writelock.acquire(); 34 | } 35 | self.lock.release(); 36 | } 37 | 38 | pub fn release_readlock(&mut self) { 39 | self.lock.acquire(); 40 | self.readers -= 1; 41 | if self.readers == 0 { 42 | self.writelock.release(); 43 | } 44 | self.lock.release(); 45 | } 46 | 47 | pub fn acquire_writelock(&self) { 48 | self.writelock.acquire(); 49 | } 50 | 51 | pub fn release_writelock(&self) { 52 | self.writelock.release(); 53 | } 54 | } 55 | 56 | fn reader(read_loops: i32) { 57 | let mut local: i32 = 0; 58 | for _i in 0..read_loops { 59 | let mut lock1 = LOCK.lock().unwrap(); 60 | lock1.acquire_readlock(); 61 | unsafe { 62 | local = COUNTER; 63 | } 64 | lock1.release_readlock(); 65 | println!("read {}", local); 66 | } 67 | println!("read done: {}", local); 68 | } 69 | 70 | fn writer(write_loops: i32) { 71 | for _i in 0..write_loops { 72 | let lock1 = LOCK.lock().unwrap(); 73 | lock1.acquire_writelock(); 74 | unsafe { 75 | COUNTER = COUNTER + 1; 76 | } 77 | lock1.release_writelock(); 78 | } 79 | println!("write done"); 80 | } 81 | 82 | fn main() { 83 | let argv = args(); 84 | let argc = argv.len(); 85 | if argc != 3 { 86 | let mut stderr = io::stderr(); 87 | stderr 88 | .write(b"usage: rwlock readloops writeloops\n") 89 | .unwrap(); 90 | std::process::exit(1); 91 | } 92 | let read_loops = args().nth(1).unwrap().parse::().unwrap(); 93 | let write_loops = args().nth(2).unwrap().parse::().unwrap(); 94 | let handle = thread::spawn(move || { 95 | reader(read_loops); 96 | }); 97 | let handle2 = thread::spawn(move || { 98 | writer(write_loops); 99 | }); 100 | handle.join().unwrap(); 101 | handle2.join().unwrap(); 102 | println!("all done"); 103 | } 104 | -------------------------------------------------------------------------------- /cpu-sched-lottery/src/bin/lottery.rs: -------------------------------------------------------------------------------- 1 | extern crate rand; 2 | use std::ptr::NonNull; 3 | use std::env::args; 4 | use std::io::{self,Write}; 5 | use rand::prelude::*; 6 | //use rand_pcg::Pcg64; 7 | struct node_t{ 8 | ticket:i32, 9 | next: Option> 10 | } 11 | 12 | impl node_t{ 13 | pub fn new(tickets:i32)->Self{ 14 | Self{ 15 | ticket:tickets, 16 | next : None 17 | } 18 | } 19 | } 20 | struct linklist{ 21 | head:Option>, 22 | gtickets:i32 23 | } 24 | 25 | impl linklist{ 26 | pub fn new()->Self{ 27 | linklist{ 28 | head : None, 29 | gtickets:0 30 | } 31 | } 32 | fn insert(&mut self,ticket:i32){ 33 | let mut node = node_t::new(ticket); 34 | let ptr = NonNull::::new(&mut node as *mut _); 35 | if let Some(head) = self.head{ 36 | node.next = unsafe{(*head.as_ptr()).next}; 37 | } 38 | self.head = ptr; 39 | self.gtickets = self.gtickets + 1; 40 | 41 | } 42 | } 43 | fn print_list(L:&linklist){ 44 | println!("List:"); 45 | let mut curr = L.head; 46 | while let Some(p) = curr{ 47 | unsafe{ 48 | println!("[{}]",(*p.as_ptr()).ticket); 49 | curr = (*p.as_ptr()).next; 50 | } 51 | } 52 | } 53 | fn main(){ 54 | let argc = args().len(); 55 | //println!("{:?}",argv.nth(2)); 56 | let mut L = linklist::new(); 57 | if argc != 3{ 58 | let mut stderr = io::stderr(); 59 | stderr.write(b"usage: lottery \n"); 60 | std::process::exit(1); 61 | } 62 | else{ 63 | println!("{:?}",args().nth(1)); 64 | println!("{:?}",args().nth(2)); 65 | let seed = args().nth(1).unwrap().parse::().unwrap(); 66 | println!("{}",seed); 67 | let loops = args().nth(2).unwrap().parse::().unwrap(); 68 | println!("{}",loops); 69 | L.insert(50); 70 | L.insert(100); 71 | L.insert(25); 72 | L.insert(200); 73 | print_list(&L); 74 | 75 | for i in 0..loops{ 76 | let mut counter = 0; 77 | let winner = rand::random::()% (L.gtickets); 78 | let mut curr = L.head; 79 | while let Some(p) = curr{ 80 | unsafe{ 81 | counter = counter + (*p.as_ptr()).ticket; 82 | } 83 | if counter > winner{ 84 | break; 85 | } 86 | unsafe{ 87 | curr = (*p.as_ptr()).next; 88 | } 89 | /*counter = counter + current->tickets; 90 | if (counter > winner) 91 | break; // found the winner 92 | current = current->next;*/ 93 | } 94 | print_list(&L); 95 | } 96 | } 97 | } 98 | 99 | /* 100 | int 101 | main(int argc, char *argv[]) 102 | { 103 | if (argc != 3) { 104 | fprintf(stderr, "usage: lottery \n"); 105 | exit(1); 106 | } 107 | int seed = atoi(argv[1]); 108 | int loops = atoi(argv[2]); 109 | srandom(seed); 110 | 111 | // populate list with some number of jobs, each 112 | // with some number of tickets 113 | insert(50); 114 | insert(100); 115 | insert(25); 116 | 117 | print_list(); 118 | 119 | int i; 120 | for (i = 0; i < loops; i++) { 121 | int counter = 0; 122 | int winner = random() % gtickets; // get winner 123 | struct node_t *current = head; 124 | 125 | // loop until the sum of ticket values is > the winner 126 | while (current) { 127 | counter = counter + current->tickets; 128 | if (counter > winner) 129 | break; // found the winner 130 | current = current->next; 131 | } 132 | // current is the winner: schedule it... 133 | print_list(); 134 | printf("winner: %d %d\n\n", winner, current->tickets); 135 | 136 | } 137 | return 0; 138 | } 139 | */ --------------------------------------------------------------------------------