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.

483 lines
12KB

  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. //==============================================================================
  252. // if this file doesn't exist, find a parent of it that does..
  253. static bool doStatFS (const File* file, struct statfs& result) throw()
  254. {
  255. File f (*file);
  256. for (int i = 5; --i >= 0;)
  257. {
  258. if (f.exists())
  259. break;
  260. f = f.getParentDirectory();
  261. }
  262. return statfs (f.getFullPathName().toUTF8(), &result) == 0;
  263. }
  264. int64 File::getBytesFreeOnVolume() const throw()
  265. {
  266. int64 free_space = 0;
  267. struct statfs buf;
  268. if (doStatFS (this, buf))
  269. // Note: this returns space available to non-super user
  270. free_space = (int64) buf.f_bsize * (int64) buf.f_bavail;
  271. return free_space;
  272. }
  273. const String juce_getVolumeLabel (const String& filenameOnVolume,
  274. int& volumeSerialNumber) throw()
  275. {
  276. volumeSerialNumber = 0;
  277. #if JUCE_MAC
  278. struct VolAttrBuf
  279. {
  280. u_int32_t length;
  281. attrreference_t mountPointRef;
  282. char mountPointSpace [MAXPATHLEN];
  283. } attrBuf;
  284. struct attrlist attrList;
  285. zerostruct (attrList);
  286. attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
  287. attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_NAME;
  288. File f (filenameOnVolume);
  289. for (;;)
  290. {
  291. if (getattrlist ((const char*) f.getFullPathName().toUTF8(),
  292. &attrList, &attrBuf, sizeof(attrBuf), 0) == 0)
  293. {
  294. return String::fromUTF8 (((const uint8*) &attrBuf.mountPointRef) + attrBuf.mountPointRef.attr_dataoffset,
  295. (int) attrBuf.mountPointRef.attr_length);
  296. }
  297. const File parent (f.getParentDirectory());
  298. if (f == parent)
  299. break;
  300. f = parent;
  301. }
  302. #endif
  303. return String::empty;
  304. }
  305. //==============================================================================
  306. #if JUCE_64BIT
  307. #define filedesc ((long long) internal)
  308. #else
  309. #define filedesc ((int) internal)
  310. #endif
  311. InterProcessLock::InterProcessLock (const String& name_) throw()
  312. : internal (0),
  313. name (name_),
  314. reentrancyLevel (0)
  315. {
  316. #if JUCE_MAC
  317. // (don't use getSpecialLocation() to avoid the temp folder being different for each app)
  318. const File temp (File (T("~/Library/Caches/Juce")).getChildFile (name));
  319. #else
  320. const File temp (File::getSpecialLocation (File::tempDirectory).getChildFile (name));
  321. #endif
  322. temp.create();
  323. internal = (void*) open (temp.getFullPathName().toUTF8(), O_RDWR);
  324. }
  325. InterProcessLock::~InterProcessLock() throw()
  326. {
  327. while (reentrancyLevel > 0)
  328. this->exit();
  329. close (filedesc);
  330. }
  331. bool InterProcessLock::enter (const int timeOutMillisecs) throw()
  332. {
  333. if (internal == 0)
  334. return false;
  335. if (reentrancyLevel != 0)
  336. return true;
  337. const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
  338. struct flock fl;
  339. zerostruct (fl);
  340. fl.l_whence = SEEK_SET;
  341. fl.l_type = F_WRLCK;
  342. for (;;)
  343. {
  344. const int result = fcntl (filedesc, F_SETLK, &fl);
  345. if (result >= 0)
  346. {
  347. ++reentrancyLevel;
  348. return true;
  349. }
  350. if (errno != EINTR)
  351. {
  352. if (timeOutMillisecs == 0
  353. || (timeOutMillisecs > 0 && Time::currentTimeMillis() >= endTime))
  354. break;
  355. Thread::sleep (10);
  356. }
  357. }
  358. return false;
  359. }
  360. void InterProcessLock::exit() throw()
  361. {
  362. if (reentrancyLevel > 0 && internal != 0)
  363. {
  364. --reentrancyLevel;
  365. struct flock fl;
  366. zerostruct (fl);
  367. fl.l_whence = SEEK_SET;
  368. fl.l_type = F_UNLCK;
  369. for (;;)
  370. {
  371. const int result = fcntl (filedesc, F_SETLKW, &fl);
  372. if (result >= 0 || errno != EINTR)
  373. break;
  374. }
  375. }
  376. }