{"action":"created","issue":{"url":"https://api.github.com/repos/zonyitoo/coio-rs/issues/19","labels_url":"https://api.github.com/repos/zonyitoo/coio-rs/issues/19/labels{/name}","comments_url":"https://api.github.com/repos/zonyitoo/coio-rs/issues/19/comments","events_url":"https://api.github.com/repos/zonyitoo/coio-rs/issues/19/events","html_url":"https://github.com/zonyitoo/coio-rs/issues/19","id":123904338,"number":19,"title":"Bad design of wait list","user":{"login":"zonyitoo","id":1067951,"avatar_url":"https://avatars.githubusercontent.com/u/1067951?v=3","gravatar_id":"","url":"https://api.github.com/users/zonyitoo","html_url":"https://github.com/zonyitoo","followers_url":"https://api.github.com/users/zonyitoo/followers","following_url":"https://api.github.com/users/zonyitoo/following{/other_user}","gists_url":"https://api.github.com/users/zonyitoo/gists{/gist_id}","starred_url":"https://api.github.com/users/zonyitoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zonyitoo/subscriptions","organizations_url":"https://api.github.com/users/zonyitoo/orgs","repos_url":"https://api.github.com/users/zonyitoo/repos","events_url":"https://api.github.com/users/zonyitoo/events{/privacy}","received_events_url":"https://api.github.com/users/zonyitoo/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/zonyitoo/coio-rs/labels/bug","name":"bug","color":"fc2929"},{"url":"https://api.github.com/repos/zonyitoo/coio-rs/labels/help%20wanted","name":"help wanted","color":"159818"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":6,"created_at":"2015-12-26T02:13:51Z","updated_at":"2015-12-26T20:03:17Z","closed_at":null,"body":"In `sync/mpsc.rs`\r\n\r\n```rust\r\nimpl<T> Receiver<T> {\r\n    pub fn recv(&self) -> Result<T, RecvError> {\r\n        loop {\r\n            // 1. Try receive\r\n            match self.try_recv() {\r\n                Ok(v) => return Ok(v),\r\n                Err(TryRecvError::Empty) => {}\r\n                Err(TryRecvError::Disconnected) => return Err(RecvError),\r\n            }\r\n\r\n            {\r\n                // 2. Lock the wait list\r\n                let mut wait_list = self.wait_list.lock().unwrap();\r\n\r\n                // 3. Try to receive again, to ensure no one sent items into the queue while\r\n                //    we are locking the wait list\r\n                match self.try_recv() {\r\n                    Ok(v) => return Ok(v),\r\n                    Err(TryRecvError::Empty) => {}\r\n                    Err(TryRecvError::Disconnected) => return Err(RecvError),\r\n                }\r\n\r\n                // 4. Push ourselves into the wait list\r\n                wait_list.push_back(unsafe {\r\n                    Processor::current().running().expect(\"A running coroutine is required!\")\r\n                });\r\n\r\n                // 5. Release the wait list\r\n            }\r\n\r\n            // NOTE: WHAT IF the thread is switched right here?\r\n            // Then the other thread may get the coroutine in the `wait_list`, and insert it by `Processor::ready`\r\n            // and wake it up while it is still not blocked.\r\n            // CRASH!\r\n\r\n            // 6. Yield\r\n            Scheduler::block();\r\n        }\r\n    }\r\n}\r\n```"},"comment":{"url":"https://api.github.com/repos/zonyitoo/coio-rs/issues/comments/167356837","html_url":"https://github.com/zonyitoo/coio-rs/issues/19#issuecomment-167356837","issue_url":"https://api.github.com/repos/zonyitoo/coio-rs/issues/19","id":167356837,"user":{"login":"lhecker","id":2256941,"avatar_url":"https://avatars.githubusercontent.com/u/2256941?v=3","gravatar_id":"","url":"https://api.github.com/users/lhecker","html_url":"https://github.com/lhecker","followers_url":"https://api.github.com/users/lhecker/followers","following_url":"https://api.github.com/users/lhecker/following{/other_user}","gists_url":"https://api.github.com/users/lhecker/gists{/gist_id}","starred_url":"https://api.github.com/users/lhecker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lhecker/subscriptions","organizations_url":"https://api.github.com/users/lhecker/orgs","repos_url":"https://api.github.com/users/lhecker/repos","events_url":"https://api.github.com/users/lhecker/events{/privacy}","received_events_url":"https://api.github.com/users/lhecker/received_events","type":"User","site_admin":false},"created_at":"2015-12-26T20:03:17Z","updated_at":"2015-12-26T20:03:17Z","body":"Yep I think I understood the distinction between Scheduler/Processor/Coroutine...\r\nBut is my proposal of introducing a `Processor::block_and_unlock()` using semaphores feasible? And if so: Is it any better than your current more generic approach in the `Processor::resume()` method?\r\n\r\nI studied the Go code a bit more and the way the channel works is basically (for e.g. sending - \"translated\" to the names used in coio):\r\n\r\n----\r\nChannel:\r\n* Lock a Mutex `lock` on the channel (We don't need this since Rust's channel is thread safe)\r\n* If \"try_recv\" is successful unlock `lock` and return (see first point)\r\n* Add a reference to the current coroutine in to a \"waiting\" field on the Processor (AFAIK this is mainly for their `select()` implementation)\r\n* Enqueue a reference to the coroutine in a send-waiting-list for the channel\r\n* Call `goparkunlock()` with the currently held `lock`\r\n\r\n----\r\n→ Go Runtime\r\n* Check and set states on the Processor and current Coroutine - also stores a (weak) reference to the lock which was passed (the `lock` above). (`acquirem()` and `releasem()` use ref-counting to lock the \"Processor\" (called *M*achine in Go) but I don't think that matters here)\r\n* **Important part**: Calls `mcall(park_m)` which switches the current context with the scheduler's context (e.g. `main_coro`) and (*after* the switch) calls the passed callback (here: `park_m`)\r\n* `park_m` *now* sets the Coroutine state back from running to waiting, disconnects it's dependency to the current Processor and *optionally* calls the unlock function for the stored reference to the lock.\r\n\r\nThis is basically nearly what I had in mind: Allocating a Lock on the stack or with some object (e.g. `Sender`/`Receiver`) or sth., pass it as a optional reference (a nullable pointer?) to the park/block method, which in turn unlocks it after the context switch (if it was passed). :blush: \r\n\r\nWhat do you think about this? Is it any better then your workaround?"}}