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.

517 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. int result = system ((const char*) command.toUTF8());
  320. (void) result;
  321. }
  322. const String juce_getOutputFromCommand (const String& command)
  323. {
  324. // slight bodge here, as we just pipe the output into a temp file and read it...
  325. const File tempFile (File::getSpecialLocation (File::tempDirectory)
  326. .getNonexistentChildFile (String::toHexString (Random::getSystemRandom().nextInt()), ".tmp", false));
  327. juce_runSystemCommand (command + " > " + tempFile.getFullPathName());
  328. String result (tempFile.loadFileAsString());
  329. tempFile.deleteFile();
  330. return result;
  331. }
  332. //==============================================================================
  333. #if JUCE_64BIT
  334. #define filedesc ((long long) internal)
  335. #else
  336. #define filedesc ((int) internal)
  337. #endif
  338. InterProcessLock::InterProcessLock (const String& name_) throw()
  339. : internal (0),
  340. name (name_),
  341. reentrancyLevel (0)
  342. {
  343. #if JUCE_MAC
  344. // (don't use getSpecialLocation() to avoid the temp folder being different for each app)
  345. const File temp (File (T("~/Library/Caches/Juce")).getChildFile (name));
  346. #else
  347. const File temp (File::getSpecialLocation (File::tempDirectory).getChildFile (name));
  348. #endif
  349. temp.create();
  350. internal = (void*) open (temp.getFullPathName().toUTF8(), O_RDWR);
  351. }
  352. InterProcessLock::~InterProcessLock() throw()
  353. {
  354. while (reentrancyLevel > 0)
  355. this->exit();
  356. close (filedesc);
  357. }
  358. bool InterProcessLock::enter (const int timeOutMillisecs) throw()
  359. {
  360. if (internal == 0)
  361. return false;
  362. if (reentrancyLevel != 0)
  363. return true;
  364. const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
  365. struct flock fl;
  366. zerostruct (fl);
  367. fl.l_whence = SEEK_SET;
  368. fl.l_type = F_WRLCK;
  369. for (;;)
  370. {
  371. const int result = fcntl (filedesc, F_SETLK, &fl);
  372. if (result >= 0)
  373. {
  374. ++reentrancyLevel;
  375. return true;
  376. }
  377. if (errno != EINTR)
  378. {
  379. if (timeOutMillisecs == 0
  380. || (timeOutMillisecs > 0 && Time::currentTimeMillis() >= endTime))
  381. break;
  382. Thread::sleep (10);
  383. }
  384. }
  385. return false;
  386. }
  387. void InterProcessLock::exit() throw()
  388. {
  389. if (reentrancyLevel > 0 && internal != 0)
  390. {
  391. --reentrancyLevel;
  392. struct flock fl;
  393. zerostruct (fl);
  394. fl.l_whence = SEEK_SET;
  395. fl.l_type = F_UNLCK;
  396. for (;;)
  397. {
  398. const int result = fcntl (filedesc, F_SETLKW, &fl);
  399. if (result >= 0 || errno != EINTR)
  400. break;
  401. }
  402. }
  403. }