{"action":"opened","issue":{"url":"https://api.github.com/repos/ahoward/open4/issues/26","labels_url":"https://api.github.com/repos/ahoward/open4/issues/26/labels{/name}","comments_url":"https://api.github.com/repos/ahoward/open4/issues/26/comments","events_url":"https://api.github.com/repos/ahoward/open4/issues/26/events","html_url":"https://github.com/ahoward/open4/issues/26","id":57973770,"number":26,"title":"Thread#pid triggers deadlock following failed call to Open4::background","user":{"login":"chrisvroberts","id":2070390,"avatar_url":"https://avatars.githubusercontent.com/u/2070390?v=3","gravatar_id":"","url":"https://api.github.com/users/chrisvroberts","html_url":"https://github.com/chrisvroberts","followers_url":"https://api.github.com/users/chrisvroberts/followers","following_url":"https://api.github.com/users/chrisvroberts/following{/other_user}","gists_url":"https://api.github.com/users/chrisvroberts/gists{/gist_id}","starred_url":"https://api.github.com/users/chrisvroberts/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/chrisvroberts/subscriptions","organizations_url":"https://api.github.com/users/chrisvroberts/orgs","repos_url":"https://api.github.com/users/chrisvroberts/repos","events_url":"https://api.github.com/users/chrisvroberts/events{/privacy}","received_events_url":"https://api.github.com/users/chrisvroberts/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-02-17T20:00:47Z","updated_at":"2015-02-17T20:00:47Z","closed_at":null,"body":"If Open4::background fails to spawn a thread then calling #pid on the returned Thread object results in a deadlock. For example, if the command executable does not exist and an Errno::ENOENT exception is raised:\r\n```\r\nrequire 'open4'\r\n> true\r\nthread = Open4.background \"non-existent-cmd\"\r\n> #<Thread:0x252fb70 run>\r\nthread.pid\r\n> fatal: deadlock detected\r\n```\r\nIn this, and any similar cases, Open4 could define a sentinel pid value that Thread#pid would return rather than blocking indefinitely. The current implementation of #pid means this could not be nil as this would result in multiple calls to Queue#pop if Thread#pid is called more than once.\r\n\r\nWhile the user can check whether the thread is alive (via Thread#alive?) a race condition exists between performing this check and calling Thread#pid.\r\n\r\nA user can't reliably work around this by calling Thread#pid within a Timeout::timeout block as this also results in a deadlock on some platforms."}}