diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..15cb33b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "playground-rs" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ff4aca8 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,8 @@ +mod server; +mod thread_pool; + +use server::run; + +fn main() { + run(); +} \ No newline at end of file diff --git a/src/server.rs b/src/server.rs new file mode 100644 index 0000000..336ef81 --- /dev/null +++ b/src/server.rs @@ -0,0 +1,25 @@ +use std::net::{TcpListener, TcpStream}; +use std::io::prelude::*; + +use crate::thread_pool::ThreadPool; + +pub fn run() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + let pool = ThreadPool::new(4); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + pool.execute(|| { + handle_execution(stream); + }); + } +} + +fn handle_execution(mut stream: TcpStream) { + let mut buffer = [0; 512]; + stream.read(&mut buffer).unwrap(); + + let response = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, world!"; + stream.write(response.as_bytes()).unwrap(); + stream.flush().unwrap(); +} \ No newline at end of file diff --git a/src/thread_pool.rs b/src/thread_pool.rs new file mode 100644 index 0000000..f10ac0d --- /dev/null +++ b/src/thread_pool.rs @@ -0,0 +1,95 @@ +use std::thread; +use std::sync::{mpsc, Arc, Mutex}; + +pub struct ThreadPool { + workers: Vec, + sender: Option>, +} + +type Job = Box; + +enum Message { + NewJob(Job), + Terminate, +} + +impl ThreadPool { + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = mpsc::channel(); + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { + workers, + sender: Some(sender), + } + } + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + if let Some(sender) = &self.sender { + sender.send(Message::NewJob(Box::new(f))).unwrap(); + } + } +} + +impl Drop for ThreadPool { + fn drop(&mut self) { + println!("Sending terminate message to all workers."); + + // Send a terminate message to each worker + if let Some(sender) = self.sender.take() { + for _ in &self.workers { + sender.send(Message::Terminate).unwrap(); + } + } + + println!("Shutting down all workers."); + + for worker in &mut self.workers { + println!("Shutting down worker {}", worker.id); + + if let Some(thread) = worker.thread.take() { + thread.join().unwrap(); + } + } + } +} + +struct Worker { + id: usize, + thread: Option>, +} + +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + let thread = thread::spawn(move || loop { + let message = receiver.lock().unwrap().recv().unwrap(); + + match message { + Message::NewJob(job) => { + println!("Worker {id} got a job; executing."); + job(); + } + Message::Terminate => { + println!("Worker {id} was told to terminate."); + break; + } + } + }); + + Worker { + id, + thread: Some(thread), + } + } +} \ No newline at end of file