utils.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2010, 2012-2017 Université de Bordeaux
  4. * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 CNRS
  5. *
  6. * StarPU is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation; either version 2.1 of the License, or (at
  9. * your option) any later version.
  10. *
  11. * StarPU is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. *
  15. * See the GNU Lesser General Public License in COPYING.LGPL for more details.
  16. */
  17. #include <starpu.h>
  18. #include <common/config.h>
  19. #include <common/utils.h>
  20. #include <core/workers.h>
  21. #include <errno.h>
  22. #ifdef HAVE_UNISTD_H
  23. #include <unistd.h>
  24. #endif
  25. #include <fcntl.h>
  26. #if defined(_WIN32) && !defined(__CYGWIN__)
  27. #include <io.h>
  28. #include <sys/locking.h>
  29. #define mkdir(path, mode) mkdir(path)
  30. #if !defined(__MINGW32__)
  31. #define ftruncate(fd, length) _chsize(fd, length)
  32. #endif
  33. #endif
  34. #ifndef O_BINARY
  35. #define O_BINARY 0
  36. #endif
  37. #if !defined(O_DIRECT) && defined(F_NOCACHE)
  38. #define O_DIRECT F_NOCACHE
  39. #endif
  40. int _starpu_silent;
  41. void _starpu_util_init(void)
  42. {
  43. _starpu_silent = starpu_get_env_number_default("STARPU_SILENT", 0);
  44. STARPU_HG_DISABLE_CHECKING(_starpu_silent);
  45. }
  46. #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
  47. #include <direct.h>
  48. static char * dirname(char * path)
  49. {
  50. char drive[_MAX_DRIVE];
  51. char dir[_MAX_DIR];
  52. /* Remove trailing slash */
  53. while (strlen(path) > 0 && (*(path+strlen(path)-1) == '/' || *(path+strlen(path)-1) == '\\'))
  54. *(path+strlen(path)-1) = '\0';
  55. _splitpath(path, drive, dir, NULL, NULL);
  56. _makepath(path, drive, dir, NULL, NULL);
  57. return path;
  58. }
  59. #else
  60. #include <libgen.h>
  61. #endif
  62. /* Function with behaviour like `mkdir -p'. This function was adapted from
  63. * http://niallohiggins.com/2009/01/08/mkpath-mkdir-p-alike-in-c-for-unix/ */
  64. int _starpu_mkpath(const char *s, mode_t mode)
  65. {
  66. int olderrno;
  67. char *q, *r = NULL, *path = NULL, *up = NULL;
  68. int rv;
  69. rv = -1;
  70. if (strcmp(s, ".") == 0 || strcmp(s, "/") == 0
  71. #if defined(_WIN32)
  72. /* C:/ or C:\ */
  73. || (s[0] && s[1] == ':' && (s[2] == '/' || s[2] == '\\') && !s[3])
  74. #endif
  75. )
  76. return 0;
  77. if ((path = strdup(s)) == NULL)
  78. STARPU_ABORT();
  79. if ((q = strdup(s)) == NULL)
  80. STARPU_ABORT();
  81. if ((r = dirname(q)) == NULL)
  82. goto out;
  83. if ((up = strdup(r)) == NULL)
  84. STARPU_ABORT();
  85. if ((_starpu_mkpath(up, mode) == -1) && (errno != EEXIST))
  86. goto out;
  87. struct stat sb;
  88. if (stat(path, &sb) == 0)
  89. {
  90. if (!S_ISDIR(sb.st_mode))
  91. {
  92. _STARPU_MSG("Error: %s is not a directory:\n", path);
  93. STARPU_ABORT();
  94. }
  95. /* It already exists and is a directory. */
  96. rv = 0;
  97. }
  98. else
  99. {
  100. if ((mkdir(path, mode) == -1) && (errno != EEXIST))
  101. rv = -1;
  102. else
  103. rv = 0;
  104. }
  105. out:
  106. olderrno = errno;
  107. if (up)
  108. free(up);
  109. free(q);
  110. free(path);
  111. errno = olderrno;
  112. return rv;
  113. }
  114. void _starpu_mkpath_and_check(const char *path, mode_t mode)
  115. {
  116. int ret;
  117. ret = _starpu_mkpath(path, mode);
  118. if (ret == -1 && errno != EEXIST)
  119. {
  120. _STARPU_MSG("Error making StarPU directory %s:\n", path);
  121. perror("mkdir");
  122. STARPU_ABORT();
  123. }
  124. }
  125. char *_starpu_mkdtemp_internal(char *tmpl)
  126. {
  127. int len = (int)strlen(tmpl);
  128. int i;
  129. int count = 1;
  130. int ret;
  131. int first_letter = (int)'a';
  132. int nb_letters = 25;
  133. int len_template = 6;
  134. // Initialize template
  135. for(i=len-len_template ; i<len ; i++)
  136. {
  137. STARPU_ASSERT_MSG(tmpl[i] == 'X', "Template must terminate by XXXXXX\n");
  138. tmpl[i] = (char) (first_letter + starpu_lrand48() % nb_letters);
  139. }
  140. // Try to create directory
  141. ret = mkdir(tmpl, 0777);
  142. while ((ret == -1) && (errno == EEXIST))
  143. {
  144. // Generate a new name
  145. for(i=len-len_template ; i<len ; i++)
  146. {
  147. tmpl[i] = (char) (first_letter + starpu_lrand48() % nb_letters);
  148. }
  149. count ++;
  150. if (count == 1000)
  151. {
  152. // We consider that after 1000 tries, we will not be able to create a directory
  153. _STARPU_MSG("Error making StarPU temporary directory\n");
  154. return NULL;
  155. }
  156. ret = mkdir(tmpl, 0777);
  157. }
  158. return tmpl;
  159. }
  160. char *_starpu_mkdtemp(char *tmpl)
  161. {
  162. #if defined(HAVE_MKDTEMP)
  163. return mkdtemp(tmpl);
  164. #else
  165. return _starpu_mkdtemp_internal(tmpl);
  166. #endif
  167. }
  168. char *_starpu_mktemp(const char *directory, int flags, int *fd)
  169. {
  170. /* create template for mkstemp */
  171. const char *tmp = "STARPU_XXXXXX";
  172. char *baseCpy;
  173. _STARPU_MALLOC(baseCpy, strlen(directory)+1+strlen(tmp)+1);
  174. snprintf(baseCpy, strlen(directory)+1+strlen(tmp)+1, "%s/%s", directory, tmp);
  175. #if defined(STARPU_HAVE_WINDOWS)
  176. _mktemp(baseCpy);
  177. *fd = open(baseCpy, flags);
  178. #elif defined (HAVE_MKOSTEMP)
  179. flags &= ~O_RDWR;
  180. *fd = mkostemp(baseCpy, flags);
  181. #else
  182. # ifdef O_DIRECT
  183. STARPU_ASSERT(flags == (O_RDWR | O_BINARY) || flags == (O_RDWR | O_BINARY | O_DIRECT));
  184. # else
  185. STARPU_ASSERT(flags == (O_RDWR | O_BINARY));
  186. # endif
  187. *fd = mkstemp(baseCpy);
  188. #endif
  189. /* fail */
  190. if (*fd < 0)
  191. {
  192. int err = errno;
  193. _STARPU_DISP("Could not create temporary file in directory '%s', mk[o]stemp failed with error '%s'\n", directory, strerror(errno));
  194. free(baseCpy);
  195. errno = err;
  196. return NULL;
  197. }
  198. #if !defined(STARPU_HAVE_WINDOWS) && !defined (HAVE_MKOSTEMP) && defined(O_DIRECT)
  199. /* Add O_DIRECT after the mkstemp call */
  200. if ((flags & O_DIRECT) != 0)
  201. {
  202. int flag = fcntl(*fd, F_GETFL);
  203. flag |= O_DIRECT;
  204. if (fcntl(*fd, F_SETFL, flag) < 0)
  205. {
  206. int err = errno;
  207. _STARPU_DISP("Could set O_DIRECT on the temporary file in directory '%s', fcntl failed with error '%s'\n", directory, strerror(errno));
  208. free(baseCpy);
  209. errno = err;
  210. return NULL;
  211. }
  212. }
  213. #endif
  214. return baseCpy;
  215. }
  216. char *_starpu_mktemp_many(const char *directory, int depth, int flags, int *fd)
  217. {
  218. size_t len = strlen(directory);
  219. char path[len + depth*4 + 1];
  220. int i;
  221. struct stat sb;
  222. if (stat(directory, &sb) != 0)
  223. {
  224. _STARPU_DISP("Directory '%s' does not exist\n", directory);
  225. return NULL;
  226. }
  227. if (!S_ISDIR(sb.st_mode))
  228. {
  229. _STARPU_DISP("'%s' is not a directory\n", directory);
  230. return NULL;
  231. }
  232. memcpy(path, directory, len+1);
  233. for (i = 0; i < depth; i++)
  234. {
  235. int r = starpu_lrand48();
  236. int ret;
  237. path[len + i*4 + 0] = '/';
  238. path[len + i*4 + 1] = '0' + (r/1)%10;
  239. path[len + i*4 + 2] = '0' + (r/10)%10;
  240. path[len + i*4 + 3] = '0' + (r/100)%10;
  241. path[len + i*4 + 4] = 0;
  242. ret = mkdir(path, 0777);
  243. if (ret == 0)
  244. continue;
  245. if (errno == EEXIST)
  246. continue;
  247. if (errno == ENOENT)
  248. {
  249. /* D'oh, somebody removed our directories in between,
  250. * restart from scratch */
  251. i = -1;
  252. continue;
  253. }
  254. _STARPU_DISP("Could not create temporary directory '%s', mkdir failed with error '%s'\n", path, strerror(errno));
  255. return NULL;
  256. }
  257. return _starpu_mktemp(path, flags, fd);
  258. }
  259. void _starpu_rmtemp_many(char *path, int depth)
  260. {
  261. int i;
  262. for (i = 0; i < depth; i++)
  263. {
  264. path = dirname(path);
  265. if (rmdir(path) < 0 && errno != ENOTEMPTY && errno != EBUSY)
  266. _STARPU_DISP("Could not remove temporary directory '%s', rmdir failed with error '%s'\n", path, strerror(errno));
  267. }
  268. }
  269. int _starpu_ftruncate(int fd, size_t length)
  270. {
  271. return ftruncate(fd, length);
  272. }
  273. int _starpu_fftruncate(FILE *file, size_t length)
  274. {
  275. return ftruncate(fileno(file), length);
  276. }
  277. static int _starpu_warn_nolock(int err)
  278. {
  279. if (0
  280. #ifdef ENOLCK
  281. || err == ENOLCK
  282. #endif
  283. #ifdef ENOTSUP
  284. || err == ENOTSUP
  285. #endif
  286. #ifdef EOPNOTSUPP
  287. || err == EOPNOTSUPP
  288. #endif
  289. #ifdef EROFS
  290. || err == EROFS
  291. #endif
  292. )
  293. {
  294. static int warn;
  295. if (!warn)
  296. {
  297. warn = 1;
  298. _STARPU_DISP("warning: Couldn't lock performance file, StarPU home (%s, coming from $HOME or $STARPU_HOME) is probably on some network filesystem like NFS which does not support locking.\n", _starpu_get_home_path());
  299. }
  300. return 1;
  301. }
  302. return 0;
  303. }
  304. int _starpu_frdlock(FILE *file)
  305. {
  306. int ret;
  307. #if defined(_WIN32) && !defined(__CYGWIN__)
  308. do
  309. {
  310. ret = _locking(fileno(file), _LK_RLCK, 10);
  311. }
  312. while (ret == EDEADLOCK);
  313. #else
  314. struct flock lock =
  315. {
  316. .l_type = F_RDLCK,
  317. .l_whence = SEEK_SET,
  318. .l_start = 0,
  319. .l_len = 0
  320. };
  321. ret = fcntl(fileno(file), F_SETLKW, &lock);
  322. #endif
  323. if (ret != 0 && _starpu_warn_nolock(errno))
  324. return -1;
  325. STARPU_ASSERT(ret == 0);
  326. return ret;
  327. }
  328. int _starpu_frdunlock(FILE *file)
  329. {
  330. int ret;
  331. #if defined(_WIN32) && !defined(__CYGWIN__)
  332. # ifndef _LK_UNLCK
  333. # define _LK_UNLCK _LK_UNLOCK
  334. # endif
  335. ret = _lseek(fileno(file), 0, SEEK_SET);
  336. STARPU_ASSERT(ret == 0);
  337. ret = _locking(fileno(file), _LK_UNLCK, 10);
  338. #else
  339. struct flock lock =
  340. {
  341. .l_type = F_UNLCK,
  342. .l_whence = SEEK_SET,
  343. .l_start = 0,
  344. .l_len = 0
  345. };
  346. ret = fcntl(fileno(file), F_SETLKW, &lock);
  347. #endif
  348. if (ret != 0 && _starpu_warn_nolock(errno))
  349. return -1;
  350. STARPU_ASSERT(ret == 0);
  351. return ret;
  352. }
  353. int _starpu_fwrlock(FILE *file)
  354. {
  355. int ret;
  356. #if defined(_WIN32) && !defined(__CYGWIN__)
  357. ret = _lseek(fileno(file), 0, SEEK_SET);
  358. STARPU_ASSERT(ret == 0);
  359. do
  360. {
  361. ret = _locking(fileno(file), _LK_LOCK, 10);
  362. }
  363. while (ret == EDEADLOCK);
  364. #else
  365. struct flock lock =
  366. {
  367. .l_type = F_WRLCK,
  368. .l_whence = SEEK_SET,
  369. .l_start = 0,
  370. .l_len = 0
  371. };
  372. ret = fcntl(fileno(file), F_SETLKW, &lock);
  373. #endif
  374. if (ret != 0 && _starpu_warn_nolock(errno))
  375. return -1;
  376. STARPU_ASSERT(ret == 0);
  377. return ret;
  378. }
  379. int _starpu_fwrunlock(FILE *file)
  380. {
  381. return _starpu_frdunlock(file);
  382. }
  383. int _starpu_check_mutex_deadlock(starpu_pthread_mutex_t *mutex)
  384. {
  385. int ret;
  386. ret = starpu_pthread_mutex_trylock(mutex);
  387. if (!ret)
  388. {
  389. STARPU_PTHREAD_MUTEX_UNLOCK(mutex);
  390. return 0;
  391. }
  392. if (ret == EBUSY)
  393. return 0;
  394. STARPU_ASSERT (ret != EDEADLK);
  395. return 1;
  396. }
  397. char *_starpu_get_home_path(void)
  398. {
  399. char *path = starpu_getenv("XDG_CACHE_HOME");
  400. if (!path)
  401. path = starpu_getenv("STARPU_HOME");
  402. #ifdef _WIN32
  403. if (!path)
  404. path = starpu_getenv("LOCALAPPDATA");
  405. if (!path)
  406. path = starpu_getenv("USERPROFILE");
  407. #endif
  408. if (!path)
  409. path = starpu_getenv("HOME");
  410. if (!path)
  411. {
  412. static int warn;
  413. path = starpu_getenv("TMPDIR");
  414. if (!path)
  415. path = starpu_getenv("TEMP");
  416. if (!path)
  417. path = starpu_getenv("TMP");
  418. if (!path)
  419. path = "/tmp";
  420. if (!warn)
  421. {
  422. warn = 1;
  423. _STARPU_DISP("couldn't find a $STARPU_HOME place to put .starpu data, using %s\n", path);
  424. }
  425. }
  426. return path;
  427. }
  428. void _starpu_gethostname(char *hostname, size_t size)
  429. {
  430. char *forced_hostname = starpu_getenv("STARPU_HOSTNAME");
  431. if (forced_hostname && forced_hostname[0])
  432. {
  433. snprintf(hostname, size-1, "%s", forced_hostname);
  434. hostname[size-1] = 0;
  435. }
  436. else
  437. {
  438. char *c;
  439. gethostname(hostname, size-1);
  440. hostname[size-1] = 0;
  441. c = strchr(hostname, '.');
  442. if (c)
  443. *c = 0;
  444. }
  445. }
  446. void starpu_sleep(float nb_sec)
  447. {
  448. #ifdef STARPU_SIMGRID
  449. MSG_process_sleep(nb_sec);
  450. #elif defined(STARPU_HAVE_WINDOWS)
  451. Sleep(nb_sec * 1000);
  452. #else
  453. struct timespec req, rem;
  454. req.tv_sec = nb_sec;
  455. req.tv_nsec = (nb_sec - (float) req.tv_sec) * 1000000000;
  456. while (nanosleep(&req, &rem))
  457. req = rem;
  458. #endif
  459. }
  460. char *starpu_getenv(const char *str)
  461. {
  462. #ifndef STARPU_SIMGRID
  463. #if defined(STARPU_DEVEL) || defined(STARPU_DEBUG)
  464. struct _starpu_worker * worker;
  465. worker = _starpu_get_local_worker_key();
  466. if (worker && worker->worker_is_initialized)
  467. _STARPU_DISP( "getenv should not be called from running workers, only for main() or worker initialization, since it is not reentrant\n");
  468. #endif
  469. #endif
  470. return getenv(str);
  471. }