{"id":10203,"date":"2011-07-08T07:00:00","date_gmt":"2011-07-08T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2011\/07\/08\/weve-traced-the-pipe-and-its-coming-from-inside-the-process\/"},"modified":"2011-07-08T07:00:00","modified_gmt":"2011-07-08T07:00:00","slug":"weve-traced-the-pipe-and-its-coming-from-inside-the-process","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20110708-00\/?p=10203","title":{"rendered":"We&#039;ve traced the pipe, and it&#039;s coming from inside the process!"},"content":{"rendered":"<p>\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/07\/07\/10183884.aspx\">\nWe saw last time<\/a>\none of the deadlocks you can run into when playing with pipes.\nToday we&#8217;ll look at another one:\n<\/p>\n<blockquote CLASS=\"q\"><p>\nOur program runs a helper process with stdin\/stdout\/stderr redirected.\nThe helper process takes input via stdin and prints the result\nto stdout.\nSometimes we find that the <code>Write&shy;File<\/code> from the controlling\nprocess into the stdin pipe hangs.\nCloser examination reveals that the helper process no longer exists.\nUnder these conditions, should the <code>Write&shy;File<\/code> fail,\nsince the reader is no longer available?\n<\/p><\/blockquote>\n<p>\nIf you attempt to write to a pipe when\nthere is nobody around to\ncall <code>Read&shy;File<\/code> to read the data out the other end,\nthe call to <code>Write&shy;File<\/code> should fail with the error\n<code>ERROR_BROKEN_PIPE<\/code>\n(known in Unix-land as <code>EPIPE<\/code>).\nWhat does it mean when the write pends?\nIt means that there is still somebody around who can read the data\nout of the pipe,\nbut the internal pipe buffer is full,\nso the write call waits for the reader to drain the data.\n<\/p>\n<p>\nBut the helper process no longer exists.\nMaybe it crashed or exited prematurely.\nThat means that there is nobody around to read the data out of the pipe.\nWhy, then, does the call not return immediately with an error?\n<\/p>\n<p>\nBecause there is still somebody around to read the data out of the pipe.\n<\/p>\n<blockquote CLASS=\"m\"><p>\nDid you remember to close the controlling process&#8217;s copy of the read\nend of the pipe?\n<\/p><\/blockquote>\n<p>\nIf the controlling process hasn&#8217;t closed its copy of the read end\nof the pipe, then the pipe is correct in believing that there is\nstill somebody around to read the data out of the pipe,\nnamely <i>you<\/i>.\nYou have a handle to the read end of the pipe,\nso the pipe manager cannot declare the pipe dead;\nfor all it knows,\nyou intended for the controlling process to call\n<code>Read&shy;File<\/code> to read the data out of the pipe.\nAs far as the pipe is concerned,\nyou simply haven&#8217;t gotten around to it yet,\nso the pipe waits patiently.\n<\/p>\n<blockquote CLASS=\"q\">\n<p>\nYes, our code calls <code>Close&shy;Handle<\/code> on the controlling\nprocess&#8217;s copy of the pipe handles.\nI&#8217;ve highlighted it below.\n(Error checking has been elided for simplicity.)\n<\/p>\n<pre>\n\/\/ create the pipe for stdout\/stderr\nCreatePipe(&amp;hReadPipeTmp, &amp;hWritePipeTmp, NULL, 0);\n\/\/ duplicate the handles with bInheritHandle=FALSE to prevent\n\/\/ them from being inherited\nDuplicateHandle(GetCurrentProcess(), hWritePipeTmp,\n                GetCurrentProcess(), &amp;hWritePipe,\n                0, FALSE, DUPLICATE_SAME_ACCESS);\nDuplicateHandle(GetCurrentProcess(), hReadPipeTmp,\n                GetCurrentProcess(), &amp;hReadPipe,\n                0, FALSE, DUPLICATE_SAME_ACCESS);\n\/\/ create the pipe for stdin\nCreatePipe(&amp;hHelperReadPipe, &amp;hHelperWritePipe,\n           NULL, 0);\n\/\/ disable inheritance on on the write end of the stdin pipe\nSetHandleInformation(hHelperWritePipe, HANDLE_FLAG_INHERIT, 0);\n\/\/ prepare to create the process\n... blah blah blah other stuff unrelated to handles ...\nstartupInfo.hStdInput = hHelperReadPipe;\nstartupInfo.hStdOutput = hWritePipeTmp;\nstartupInfo.hStdError = hWritePipeTmp;\nCreateProcess(...);\n\/\/ Here is where we close the handles\n<font COLOR=\"blue\">CloseHandle(hReadPipeTmp);\nCloseHandle(hWritePipeTmp);<\/font>\n\/\/ Write the input to the helper process (hangs here sometimes)\nWriteFile(hHelperWritePipe, ...);\n<\/pre>\n<\/blockquote>\n<p>\nThis is another case of\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2009\/10\/14\/9906906.aspx\">\ngetting so excited about doing something\nthat you forget to do it<\/a>.\n(Notice how the comments to that article very quickly descend\ninto a discussion of command line quotation marks.)\n<\/p>\n<p>\nObserve that the handles being closed are <code>hRead&shy;Pipe&shy;Tmp<\/code>\nand <code>hWrite&shy;Pipe&shy;Tmp<\/code>, which is a good thing to do,\nbut neither has any effect on the\n<code>Write&shy;File<\/code>.\nThe <code>Write&shy;File<\/code> is writing to\n<code>hHelper&shy;Write&shy;Pipe<\/code>\nand therefore the handle you need to close is\n<code>hHelper&shy;Read&shy;Pipe<\/code>.\nSince that handle is still open in the controlling process,\nthe pipe manager will not break the pipe,\nbecause it&#8217;s waiting for you to read from it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We saw last time one of the deadlocks you can run into when playing with pipes. Today we&#8217;ll look at another one: Our program runs a helper process with stdin\/stdout\/stderr redirected. The helper process takes input via stdin and prints the result to stdout. Sometimes we find that the Write&shy;File from the controlling process into [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-10203","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>We saw last time one of the deadlocks you can run into when playing with pipes. Today we&#8217;ll look at another one: Our program runs a helper process with stdin\/stdout\/stderr redirected. The helper process takes input via stdin and prints the result to stdout. Sometimes we find that the Write&shy;File from the controlling process into [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/10203","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=10203"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/10203\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=10203"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=10203"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=10203"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}