utils.c 13 KB

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