The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
6.4KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  24. #include <sys/stat.h>
  25. #include <sys/dir.h>
  26. #include <fcntl.h>
  27. // As well as being for the mac, this file is included by the linux build.
  28. #if JUCE_MAC
  29. #include <Carbon/Carbon.h>
  30. #else
  31. #include <sys/wait.h>
  32. #include <errno.h>
  33. #include <unistd.h>
  34. #endif
  35. BEGIN_JUCE_NAMESPACE
  36. #include "../../../src/juce_core/io/files/juce_File.h"
  37. #include "../../../src/juce_core/io/files/juce_NamedPipe.h"
  38. //==============================================================================
  39. struct NamedPipeInternal
  40. {
  41. String pipeInName, pipeOutName;
  42. int pipeIn, pipeOut;
  43. bool volatile createdPipe, blocked, stopReadOperation;
  44. static void signalHandler (int) {}
  45. };
  46. void NamedPipe::cancelPendingReads()
  47. {
  48. while (internal != 0 && ((NamedPipeInternal*) internal)->blocked)
  49. {
  50. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  51. intern->stopReadOperation = true;
  52. char buffer [1] = { 0 };
  53. ::write (intern->pipeIn, buffer, 1);
  54. int timeout = 2000;
  55. while (intern->blocked && --timeout >= 0)
  56. sleep (2);
  57. intern->stopReadOperation = false;
  58. }
  59. }
  60. void NamedPipe::close()
  61. {
  62. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  63. if (intern != 0)
  64. {
  65. internal = 0;
  66. if (intern->pipeIn != -1)
  67. ::close (intern->pipeIn);
  68. if (intern->pipeOut != -1)
  69. ::close (intern->pipeOut);
  70. if (intern->createdPipe)
  71. {
  72. unlink (intern->pipeInName);
  73. unlink (intern->pipeOutName);
  74. }
  75. delete intern;
  76. }
  77. }
  78. bool NamedPipe::openInternal (const String& pipeName, const bool createPipe)
  79. {
  80. close();
  81. NamedPipeInternal* const intern = new NamedPipeInternal();
  82. internal = intern;
  83. intern->createdPipe = createPipe;
  84. intern->blocked = false;
  85. intern->stopReadOperation = false;
  86. signal (SIGPIPE, NamedPipeInternal::signalHandler);
  87. siginterrupt (SIGPIPE, 1);
  88. const String pipePath (T("/tmp/") + File::createLegalFileName (pipeName));
  89. intern->pipeInName = pipePath + T("_in");
  90. intern->pipeOutName = pipePath + T("_out");
  91. intern->pipeIn = -1;
  92. intern->pipeOut = -1;
  93. if (createPipe)
  94. {
  95. if ((mkfifo (intern->pipeInName, 0666) && errno != EEXIST)
  96. || (mkfifo (intern->pipeOutName, 0666) && errno != EEXIST))
  97. {
  98. delete intern;
  99. internal = 0;
  100. return false;
  101. }
  102. }
  103. return true;
  104. }
  105. int NamedPipe::read (void* destBuffer, int maxBytesToRead, int /*timeOutMilliseconds*/)
  106. {
  107. int bytesRead = -1;
  108. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  109. if (intern != 0)
  110. {
  111. intern->blocked = true;
  112. if (intern->pipeIn == -1)
  113. {
  114. if (intern->createdPipe)
  115. intern->pipeIn = ::open (intern->pipeInName, O_RDWR);
  116. else
  117. intern->pipeIn = ::open (intern->pipeOutName, O_RDWR);
  118. if (intern->pipeIn == -1)
  119. {
  120. intern->blocked = false;
  121. return -1;
  122. }
  123. }
  124. bytesRead = 0;
  125. char* p = (char*) destBuffer;
  126. while (bytesRead < maxBytesToRead)
  127. {
  128. const int bytesThisTime = maxBytesToRead - bytesRead;
  129. const int numRead = ::read (intern->pipeIn, p, bytesThisTime);
  130. if (numRead <= 0 || intern->stopReadOperation)
  131. {
  132. bytesRead = -1;
  133. break;
  134. }
  135. bytesRead += numRead;
  136. p += bytesRead;
  137. }
  138. intern->blocked = false;
  139. }
  140. return bytesRead;
  141. }
  142. int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
  143. {
  144. int bytesWritten = -1;
  145. NamedPipeInternal* const intern = (NamedPipeInternal*) internal;
  146. if (intern != 0)
  147. {
  148. if (intern->pipeOut == -1)
  149. {
  150. if (intern->createdPipe)
  151. intern->pipeOut = ::open (intern->pipeOutName, O_WRONLY);
  152. else
  153. intern->pipeOut = ::open (intern->pipeInName, O_WRONLY);
  154. if (intern->pipeOut == -1)
  155. {
  156. return -1;
  157. }
  158. }
  159. const char* p = (const char*) sourceBuffer;
  160. bytesWritten = 0;
  161. const uint32 timeOutTime = Time::getMillisecondCounter() + timeOutMilliseconds;
  162. while (bytesWritten < numBytesToWrite
  163. && (timeOutMilliseconds < 0 || Time::getMillisecondCounter() < timeOutTime))
  164. {
  165. const int bytesThisTime = numBytesToWrite - bytesWritten;
  166. const int numWritten = ::write (intern->pipeOut, p, bytesThisTime);
  167. if (numWritten <= 0)
  168. {
  169. bytesWritten = -1;
  170. break;
  171. }
  172. bytesWritten += numWritten;
  173. p += bytesWritten;
  174. }
  175. }
  176. return bytesWritten;
  177. }
  178. END_JUCE_NAMESPACE