utils.c 12 KB

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