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.

516 lines
13KB

  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. /*
  24. This file contains posix routines that are common to both the Linux and Mac builds.
  25. It gets included directly in the cpp files for these platforms.
  26. */
  27. //==============================================================================
  28. CriticalSection::CriticalSection() throw()
  29. {
  30. pthread_mutexattr_t atts;
  31. pthread_mutexattr_init (&atts);
  32. pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE);
  33. pthread_mutex_init (&internal, &atts);
  34. }
  35. CriticalSection::~CriticalSection() throw()
  36. {
  37. pthread_mutex_destroy (&internal);
  38. }
  39. void CriticalSection::enter() const throw()
  40. {
  41. pthread_mutex_lock (&internal);
  42. }
  43. bool CriticalSection::tryEnter() const throw()
  44. {
  45. return pthread_mutex_trylock (&internal) == 0;
  46. }
  47. void CriticalSection::exit() const throw()
  48. {
  49. pthread_mutex_unlock (&internal);
  50. }
  51. //==============================================================================
  52. struct EventStruct
  53. {
  54. pthread_cond_t condition;
  55. pthread_mutex_t mutex;
  56. bool triggered;
  57. };
  58. WaitableEvent::WaitableEvent() throw()
  59. {
  60. EventStruct* const es = new EventStruct();
  61. es->triggered = false;
  62. pthread_cond_init (&es->condition, 0);
  63. pthread_mutex_init (&es->mutex, 0);
  64. internal = es;
  65. }
  66. WaitableEvent::~WaitableEvent() throw()
  67. {
  68. EventStruct* const es = (EventStruct*) internal;
  69. pthread_cond_destroy (&es->condition);
  70. pthread_mutex_destroy (&es->mutex);
  71. delete es;
  72. }
  73. bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
  74. {
  75. EventStruct* const es = (EventStruct*) internal;
  76. bool ok = true;
  77. pthread_mutex_lock (&es->mutex);
  78. if (timeOutMillisecs < 0)
  79. {
  80. while (! es->triggered)
  81. pthread_cond_wait (&es->condition, &es->mutex);
  82. }
  83. else
  84. {
  85. while (! es->triggered)
  86. {
  87. struct timeval t;
  88. gettimeofday (&t, 0);
  89. struct timespec time;
  90. time.tv_sec = t.tv_sec + (timeOutMillisecs / 1000);
  91. time.tv_nsec = (t.tv_usec + ((timeOutMillisecs % 1000) * 1000)) * 1000;
  92. if (time.tv_nsec >= 1000000000)
  93. {
  94. time.tv_nsec -= 1000000000;
  95. time.tv_sec++;
  96. }
  97. if (pthread_cond_timedwait (&es->condition, &es->mutex, &time) == ETIMEDOUT)
  98. {
  99. ok = false;
  100. break;
  101. }
  102. }
  103. }
  104. es->triggered = false;
  105. pthread_mutex_unlock (&es->mutex);
  106. return ok;
  107. }
  108. void WaitableEvent::signal() const throw()
  109. {
  110. EventStruct* const es = (EventStruct*) internal;
  111. pthread_mutex_lock (&es->mutex);
  112. es->triggered = true;
  113. pthread_cond_broadcast (&es->condition);
  114. pthread_mutex_unlock (&es->mutex);
  115. }
  116. void WaitableEvent::reset() const throw()
  117. {
  118. EventStruct* const es = (EventStruct*) internal;
  119. pthread_mutex_lock (&es->mutex);
  120. es->triggered = false;
  121. pthread_mutex_unlock (&es->mutex);
  122. }
  123. //==============================================================================
  124. void JUCE_CALLTYPE Thread::sleep (int millisecs) throw()
  125. {
  126. struct timespec time;
  127. time.tv_sec = millisecs / 1000;
  128. time.tv_nsec = (millisecs % 1000) * 1000000;
  129. nanosleep (&time, 0);
  130. }
  131. //==============================================================================
  132. const tchar File::separator = T('/');
  133. const tchar* File::separatorString = T("/");
  134. //==============================================================================
  135. bool juce_copyFile (const String& s, const String& d) throw();
  136. static bool juce_stat (const String& fileName, struct stat& info) throw()
  137. {
  138. return fileName.isNotEmpty()
  139. && (stat (fileName.toUTF8(), &info) == 0);
  140. }
  141. bool juce_isDirectory (const String& fileName) throw()
  142. {
  143. struct stat info;
  144. return fileName.isEmpty()
  145. || (juce_stat (fileName, info)
  146. && ((info.st_mode & S_IFDIR) != 0));
  147. }
  148. bool juce_fileExists (const String& fileName, const bool dontCountDirectories) throw()
  149. {
  150. if (fileName.isEmpty())
  151. return false;
  152. const char* const fileNameUTF8 = fileName.toUTF8();
  153. bool exists = access (fileNameUTF8, F_OK) == 0;
  154. if (exists && dontCountDirectories)
  155. {
  156. struct stat info;
  157. const int res = stat (fileNameUTF8, &info);
  158. if (res == 0 && (info.st_mode & S_IFDIR) != 0)
  159. exists = false;
  160. }
  161. return exists;
  162. }
  163. int64 juce_getFileSize (const String& fileName) throw()
  164. {
  165. struct stat info;
  166. return juce_stat (fileName, info) ? info.st_size : 0;
  167. }
  168. //==============================================================================
  169. bool juce_canWriteToFile (const String& fileName) throw()
  170. {
  171. return access (fileName.toUTF8(), W_OK) == 0;
  172. }
  173. bool juce_deleteFile (const String& fileName) throw()
  174. {
  175. if (juce_isDirectory (fileName))
  176. return rmdir ((const char*) fileName.toUTF8()) == 0;
  177. else
  178. return remove ((const char*) fileName.toUTF8()) == 0;
  179. }
  180. bool juce_moveFile (const String& source, const String& dest) throw()
  181. {
  182. if (rename (source.toUTF8(), dest.toUTF8()) == 0)
  183. return true;
  184. if (juce_canWriteToFile (source)
  185. && juce_copyFile (source, dest))
  186. {
  187. if (juce_deleteFile (source))
  188. return true;
  189. juce_deleteFile (dest);
  190. }
  191. return false;
  192. }
  193. void juce_createDirectory (const String& fileName) throw()
  194. {
  195. mkdir (fileName.toUTF8(), 0777);
  196. }
  197. void* juce_fileOpen (const String& fileName, bool forWriting) throw()
  198. {
  199. int flags = O_RDONLY;
  200. if (forWriting)
  201. {
  202. if (juce_fileExists (fileName, false))
  203. {
  204. const int f = open ((const char*) fileName.toUTF8(), O_RDWR, 00644);
  205. if (f != -1)
  206. lseek (f, 0, SEEK_END);
  207. return (void*) f;
  208. }
  209. else
  210. {
  211. flags = O_RDWR + O_CREAT;
  212. }
  213. }
  214. return (void*) open ((const char*) fileName.toUTF8(), flags, 00644);
  215. }
  216. void juce_fileClose (void* handle) throw()
  217. {
  218. if (handle != 0)
  219. close ((int) (pointer_sized_int) handle);
  220. }
  221. int juce_fileRead (void* handle, void* buffer, int size) throw()
  222. {
  223. if (handle != 0)
  224. return read ((int) (pointer_sized_int) handle, buffer, size);
  225. return 0;
  226. }
  227. int juce_fileWrite (void* handle, const void* buffer, int size) throw()
  228. {
  229. if (handle != 0)
  230. return write ((int) (pointer_sized_int) handle, buffer, size);
  231. return 0;
  232. }
  233. int64 juce_fileSetPosition (void* handle, int64 pos) throw()
  234. {
  235. if (handle != 0 && lseek ((int) (pointer_sized_int) handle, pos, SEEK_SET) == pos)
  236. return pos;
  237. return -1;
  238. }
  239. int64 juce_fileGetPosition (void* handle) throw()
  240. {
  241. if (handle != 0)
  242. return lseek ((int) (pointer_sized_int) handle, 0, SEEK_CUR);
  243. else
  244. return -1;
  245. }
  246. void juce_fileFlush (void* handle) throw()
  247. {
  248. if (handle != 0)
  249. fsync ((int) (pointer_sized_int) handle);
  250. }
  251. const File juce_getExecutableFile()
  252. {
  253. Dl_info exeInfo;
  254. dladdr ((const void*) juce_getExecutableFile, &exeInfo);
  255. return File (exeInfo.dli_fname);
  256. }
  257. //==============================================================================
  258. // if this file doesn't exist, find a parent of it that does..
  259. static bool doStatFS (const File* file, struct statfs& result) throw()
  260. {
  261. File f (*file);
  262. for (int i = 5; --i >= 0;)
  263. {
  264. if (f.exists())
  265. break;
  266. f = f.getParentDirectory();
  267. }
  268. return statfs (f.getFullPathName().toUTF8(), &result) == 0;
  269. }
  270. int64 File::getBytesFreeOnVolume() const throw()
  271. {
  272. struct statfs buf;
  273. if (doStatFS (this, buf))
  274. return (int64) buf.f_bsize * (int64) buf.f_bavail; // Note: this returns space available to non-super user
  275. return 0;
  276. }
  277. int64 File::getVolumeTotalSize() const throw()
  278. {
  279. struct statfs buf;
  280. if (doStatFS (this, buf))
  281. return (int64) buf.f_bsize * (int64) buf.f_blocks;
  282. return 0;
  283. }
  284. const String juce_getVolumeLabel (const String& filenameOnVolume,
  285. int& volumeSerialNumber) throw()
  286. {
  287. volumeSerialNumber = 0;
  288. #if JUCE_MAC
  289. struct VolAttrBuf
  290. {
  291. u_int32_t length;
  292. attrreference_t mountPointRef;
  293. char mountPointSpace [MAXPATHLEN];
  294. } attrBuf;
  295. struct attrlist attrList;
  296. zerostruct (attrList);
  297. attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
  298. attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_NAME;
  299. File f (filenameOnVolume);
  300. for (;;)
  301. {
  302. if (getattrlist ((const char*) f.getFullPathName().toUTF8(),
  303. &attrList, &attrBuf, sizeof(attrBuf), 0) == 0)
  304. {
  305. return String::fromUTF8 (((const uint8*) &attrBuf.mountPointRef) + attrBuf.mountPointRef.attr_dataoffset,
  306. (int) attrBuf.mountPointRef.attr_length);
  307. }
  308. const File parent (f.getParentDirectory());
  309. if (f == parent)
  310. break;
  311. f = parent;
  312. }
  313. #endif
  314. return String::empty;
  315. }
  316. //==============================================================================
  317. void juce_runSystemCommand (const String& command)
  318. {
  319. system ((const char*) command.toUTF8());
  320. }
  321. const String juce_getOutputFromCommand (const String& command)
  322. {
  323. // slight bodge here, as we just pipe the output into a temp file and read it...
  324. const File tempFile (File::getSpecialLocation (File::tempDirectory)
  325. .getNonexistentChildFile (String::toHexString (Random::getSystemRandom().nextInt()), ".tmp", false));
  326. juce_runSystemCommand (command + " > " + tempFile.getFullPathName());
  327. String result (tempFile.loadFileAsString());
  328. tempFile.deleteFile();
  329. return result;
  330. }
  331. //==============================================================================
  332. #if JUCE_64BIT
  333. #define filedesc ((long long) internal)
  334. #else
  335. #define filedesc ((int) internal)
  336. #endif
  337. InterProcessLock::InterProcessLock (const String& name_) throw()
  338. : internal (0),
  339. name (name_),
  340. reentrancyLevel (0)
  341. {
  342. #if JUCE_MAC
  343. // (don't use getSpecialLocation() to avoid the temp folder being different for each app)
  344. const File temp (File (T("~/Library/Caches/Juce")).getChildFile (name));
  345. #else
  346. const File temp (File::getSpecialLocation (File::tempDirectory).getChildFile (name));
  347. #endif
  348. temp.create();
  349. internal = (void*) open (temp.getFullPathName().toUTF8(), O_RDWR);
  350. }
  351. InterProcessLock::~InterProcessLock() throw()
  352. {
  353. while (reentrancyLevel > 0)
  354. this->exit();
  355. close (filedesc);
  356. }
  357. bool InterProcessLock::enter (const int timeOutMillisecs) throw()
  358. {
  359. if (internal == 0)
  360. return false;
  361. if (reentrancyLevel != 0)
  362. return true;
  363. const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
  364. struct flock fl;
  365. zerostruct (fl);
  366. fl.l_whence = SEEK_SET;
  367. fl.l_type = F_WRLCK;
  368. for (;;)
  369. {
  370. const int result = fcntl (filedesc, F_SETLK, &fl);
  371. if (result >= 0)
  372. {
  373. ++reentrancyLevel;
  374. return true;
  375. }
  376. if (errno != EINTR)
  377. {
  378. if (timeOutMillisecs == 0
  379. || (timeOutMillisecs > 0 && Time::currentTimeMillis() >= endTime))
  380. break;
  381. Thread::sleep (10);
  382. }
  383. }
  384. return false;
  385. }
  386. void InterProcessLock::exit() throw()
  387. {
  388. if (reentrancyLevel > 0 && internal != 0)
  389. {
  390. --reentrancyLevel;
  391. struct flock fl;
  392. zerostruct (fl);
  393. fl.l_whence = SEEK_SET;
  394. fl.l_type = F_UNLCK;
  395. for (;;)
  396. {
  397. const int result = fcntl (filedesc, F_SETLKW, &fl);
  398. if (result >= 0 || errno != EINTR)
  399. break;
  400. }
  401. }
  402. }