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.

453 lines
11KB

  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. const char* const fileNameUTF8 = fileName.toUTF8();
  176. if (juce_isDirectory (fileName))
  177. return rmdir (fileNameUTF8) == 0;
  178. else
  179. return remove (fileNameUTF8) == 0;
  180. }
  181. bool juce_moveFile (const String& source, const String& dest) throw()
  182. {
  183. if (rename (source.toUTF8(), dest.toUTF8()) == 0)
  184. return true;
  185. if (juce_canWriteToFile (source)
  186. && juce_copyFile (source, dest))
  187. {
  188. if (juce_deleteFile (source))
  189. return true;
  190. juce_deleteFile (dest);
  191. }
  192. return false;
  193. }
  194. void juce_createDirectory (const String& fileName) throw()
  195. {
  196. mkdir (fileName.toUTF8(), 0777);
  197. }
  198. void* juce_fileOpen (const String& fileName, bool forWriting) throw()
  199. {
  200. const char* const fileNameUTF8 = fileName.toUTF8();
  201. int flags = O_RDONLY;
  202. if (forWriting)
  203. {
  204. if (juce_fileExists (fileName, false))
  205. {
  206. const int f = open (fileNameUTF8, O_RDWR, 00644);
  207. if (f != -1)
  208. lseek (f, 0, SEEK_END);
  209. return (void*) f;
  210. }
  211. else
  212. {
  213. flags = O_RDWR + O_CREAT;
  214. }
  215. }
  216. return (void*) open (fileNameUTF8, flags, 00644);
  217. }
  218. void juce_fileClose (void* handle) throw()
  219. {
  220. if (handle != 0)
  221. close ((int) (pointer_sized_int) handle);
  222. }
  223. int juce_fileRead (void* handle, void* buffer, int size) throw()
  224. {
  225. if (handle != 0)
  226. return read ((int) (pointer_sized_int) handle, buffer, size);
  227. return 0;
  228. }
  229. int juce_fileWrite (void* handle, const void* buffer, int size) throw()
  230. {
  231. if (handle != 0)
  232. return write ((int) (pointer_sized_int) handle, buffer, size);
  233. return 0;
  234. }
  235. int64 juce_fileSetPosition (void* handle, int64 pos) throw()
  236. {
  237. if (handle != 0 && lseek ((int) (pointer_sized_int) handle, pos, SEEK_SET) == pos)
  238. return pos;
  239. return -1;
  240. }
  241. int64 juce_fileGetPosition (void* handle) throw()
  242. {
  243. if (handle != 0)
  244. return lseek ((int) (pointer_sized_int) handle, 0, SEEK_CUR);
  245. else
  246. return -1;
  247. }
  248. void juce_fileFlush (void* handle) throw()
  249. {
  250. if (handle != 0)
  251. fsync ((int) (pointer_sized_int) handle);
  252. }
  253. //==============================================================================
  254. // if this file doesn't exist, find a parent of it that does..
  255. static bool doStatFS (const File* file, struct statfs& result) throw()
  256. {
  257. File f (*file);
  258. for (int i = 5; --i >= 0;)
  259. {
  260. if (f.exists())
  261. break;
  262. f = f.getParentDirectory();
  263. }
  264. return statfs (f.getFullPathName().toUTF8(), &result) == 0;
  265. }
  266. int64 File::getBytesFreeOnVolume() const throw()
  267. {
  268. int64 free_space = 0;
  269. struct statfs buf;
  270. if (doStatFS (this, buf))
  271. // Note: this returns space available to non-super user
  272. free_space = (int64) buf.f_bsize * (int64) buf.f_bavail;
  273. return free_space;
  274. }
  275. const String juce_getVolumeLabel (const String& filenameOnVolume,
  276. int& volumeSerialNumber) throw()
  277. {
  278. // There is no equivalent on Linux
  279. volumeSerialNumber = 0;
  280. return String::empty;
  281. }
  282. //==============================================================================
  283. #if JUCE_64BIT
  284. #define filedesc ((long long) internal)
  285. #else
  286. #define filedesc ((int) internal)
  287. #endif
  288. InterProcessLock::InterProcessLock (const String& name_) throw()
  289. : internal (0),
  290. name (name_),
  291. reentrancyLevel (0)
  292. {
  293. #if JUCE_MAC
  294. // (don't use getSpecialLocation() to avoid the temp folder being different for each app)
  295. const File temp (File (T("~/Library/Caches/Juce")).getChildFile (name));
  296. #else
  297. const File temp (File::getSpecialLocation (File::tempDirectory).getChildFile (name));
  298. #endif
  299. temp.create();
  300. internal = (void*) open (temp.getFullPathName().toUTF8(), O_RDWR);
  301. }
  302. InterProcessLock::~InterProcessLock() throw()
  303. {
  304. while (reentrancyLevel > 0)
  305. this->exit();
  306. close (filedesc);
  307. }
  308. bool InterProcessLock::enter (const int timeOutMillisecs) throw()
  309. {
  310. if (internal == 0)
  311. return false;
  312. if (reentrancyLevel != 0)
  313. return true;
  314. const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs;
  315. struct flock fl;
  316. zerostruct (fl);
  317. fl.l_whence = SEEK_SET;
  318. fl.l_type = F_WRLCK;
  319. for (;;)
  320. {
  321. const int result = fcntl (filedesc, F_SETLK, &fl);
  322. if (result >= 0)
  323. {
  324. ++reentrancyLevel;
  325. return true;
  326. }
  327. if (errno != EINTR)
  328. {
  329. if (timeOutMillisecs == 0
  330. || (timeOutMillisecs > 0 && Time::currentTimeMillis() >= endTime))
  331. break;
  332. Thread::sleep (10);
  333. }
  334. }
  335. return false;
  336. }
  337. void InterProcessLock::exit() throw()
  338. {
  339. if (reentrancyLevel > 0 && internal != 0)
  340. {
  341. --reentrancyLevel;
  342. struct flock fl;
  343. zerostruct (fl);
  344. fl.l_whence = SEEK_SET;
  345. fl.l_type = F_UNLCK;
  346. for (;;)
  347. {
  348. const int result = fcntl (filedesc, F_SETLKW, &fl);
  349. if (result >= 0 || errno != EINTR)
  350. break;
  351. }
  352. }
  353. }