os390-syscalls.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. /* Copyright libuv project contributors. All rights reserved.
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to
  5. * deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  7. * sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19. * IN THE SOFTWARE.
  20. */
  21. #include "os390-syscalls.h"
  22. #include <errno.h>
  23. #include <stdlib.h>
  24. #include <search.h>
  25. #include <termios.h>
  26. #include <sys/msg.h>
  27. #define CW_INTRPT 1
  28. #define CW_CONDVAR 32
  29. #pragma linkage(BPX4CTW, OS)
  30. #pragma linkage(BPX1CTW, OS)
  31. static int number_of_epolls;
  32. static QUEUE global_epoll_queue;
  33. static uv_mutex_t global_epoll_lock;
  34. static uv_once_t once = UV_ONCE_INIT;
  35. int scandir(const char* maindir, struct dirent*** namelist,
  36. int (*filter)(const struct dirent*),
  37. int (*compar)(const struct dirent**,
  38. const struct dirent **)) {
  39. struct dirent** nl;
  40. struct dirent** nl_copy;
  41. struct dirent* dirent;
  42. unsigned count;
  43. size_t allocated;
  44. DIR* mdir;
  45. nl = NULL;
  46. count = 0;
  47. allocated = 0;
  48. mdir = opendir(maindir);
  49. if (!mdir)
  50. return -1;
  51. while (1) {
  52. dirent = readdir(mdir);
  53. if (!dirent)
  54. break;
  55. if (!filter || filter(dirent)) {
  56. struct dirent* copy;
  57. copy = uv__malloc(sizeof(*copy));
  58. if (!copy)
  59. goto error;
  60. memcpy(copy, dirent, sizeof(*copy));
  61. nl_copy = uv__realloc(nl, sizeof(*copy) * (count + 1));
  62. if (nl_copy == NULL) {
  63. uv__free(copy);
  64. goto error;
  65. }
  66. nl = nl_copy;
  67. nl[count++] = copy;
  68. }
  69. }
  70. qsort(nl, count, sizeof(struct dirent *),
  71. (int (*)(const void *, const void *)) compar);
  72. closedir(mdir);
  73. *namelist = nl;
  74. return count;
  75. error:
  76. while (count > 0) {
  77. dirent = nl[--count];
  78. uv__free(dirent);
  79. }
  80. uv__free(nl);
  81. closedir(mdir);
  82. errno = ENOMEM;
  83. return -1;
  84. }
  85. static unsigned int next_power_of_two(unsigned int val) {
  86. val -= 1;
  87. val |= val >> 1;
  88. val |= val >> 2;
  89. val |= val >> 4;
  90. val |= val >> 8;
  91. val |= val >> 16;
  92. val += 1;
  93. return val;
  94. }
  95. static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
  96. unsigned int newsize;
  97. unsigned int i;
  98. struct pollfd* newlst;
  99. struct pollfd event;
  100. if (len <= lst->size)
  101. return;
  102. if (lst->size == 0)
  103. event.fd = -1;
  104. else {
  105. /* Extract the message queue at the end. */
  106. event = lst->items[lst->size - 1];
  107. lst->items[lst->size - 1].fd = -1;
  108. }
  109. newsize = next_power_of_two(len);
  110. newlst = uv__reallocf(lst->items, newsize * sizeof(lst->items[0]));
  111. if (newlst == NULL)
  112. abort();
  113. for (i = lst->size; i < newsize; ++i)
  114. newlst[i].fd = -1;
  115. /* Restore the message queue at the end */
  116. newlst[newsize - 1] = event;
  117. lst->items = newlst;
  118. lst->size = newsize;
  119. }
  120. static void init_message_queue(uv__os390_epoll* lst) {
  121. struct {
  122. long int header;
  123. char body;
  124. } msg;
  125. /* initialize message queue */
  126. lst->msg_queue = msgget(IPC_PRIVATE, 0600 | IPC_CREAT);
  127. if (lst->msg_queue == -1)
  128. abort();
  129. /*
  130. On z/OS, the message queue will be affiliated with the process only
  131. when a send is performed on it. Once this is done, the system
  132. can be queried for all message queues belonging to our process id.
  133. */
  134. msg.header = 1;
  135. if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0)
  136. abort();
  137. /* Clean up the dummy message sent above */
  138. if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body))
  139. abort();
  140. }
  141. static void before_fork(void) {
  142. uv_mutex_lock(&global_epoll_lock);
  143. }
  144. static void after_fork(void) {
  145. uv_mutex_unlock(&global_epoll_lock);
  146. }
  147. static void child_fork(void) {
  148. QUEUE* q;
  149. uv_once_t child_once = UV_ONCE_INIT;
  150. /* reset once */
  151. memcpy(&once, &child_once, sizeof(child_once));
  152. /* reset epoll list */
  153. while (!QUEUE_EMPTY(&global_epoll_queue)) {
  154. uv__os390_epoll* lst;
  155. q = QUEUE_HEAD(&global_epoll_queue);
  156. QUEUE_REMOVE(q);
  157. lst = QUEUE_DATA(q, uv__os390_epoll, member);
  158. uv__free(lst->items);
  159. lst->items = NULL;
  160. lst->size = 0;
  161. }
  162. uv_mutex_unlock(&global_epoll_lock);
  163. uv_mutex_destroy(&global_epoll_lock);
  164. }
  165. static void epoll_init(void) {
  166. QUEUE_INIT(&global_epoll_queue);
  167. if (uv_mutex_init(&global_epoll_lock))
  168. abort();
  169. if (pthread_atfork(&before_fork, &after_fork, &child_fork))
  170. abort();
  171. }
  172. uv__os390_epoll* epoll_create1(int flags) {
  173. uv__os390_epoll* lst;
  174. lst = uv__malloc(sizeof(*lst));
  175. if (lst != NULL) {
  176. /* initialize list */
  177. lst->size = 0;
  178. lst->items = NULL;
  179. init_message_queue(lst);
  180. maybe_resize(lst, 1);
  181. lst->items[lst->size - 1].fd = lst->msg_queue;
  182. lst->items[lst->size - 1].events = POLLIN;
  183. lst->items[lst->size - 1].revents = 0;
  184. uv_once(&once, epoll_init);
  185. uv_mutex_lock(&global_epoll_lock);
  186. QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
  187. uv_mutex_unlock(&global_epoll_lock);
  188. }
  189. return lst;
  190. }
  191. int epoll_ctl(uv__os390_epoll* lst,
  192. int op,
  193. int fd,
  194. struct epoll_event *event) {
  195. uv_mutex_lock(&global_epoll_lock);
  196. if (op == EPOLL_CTL_DEL) {
  197. if (fd >= lst->size || lst->items[fd].fd == -1) {
  198. uv_mutex_unlock(&global_epoll_lock);
  199. errno = ENOENT;
  200. return -1;
  201. }
  202. lst->items[fd].fd = -1;
  203. } else if (op == EPOLL_CTL_ADD) {
  204. /* Resizing to 'fd + 1' would expand the list to contain at least
  205. * 'fd'. But we need to guarantee that the last index on the list
  206. * is reserved for the message queue. So specify 'fd + 2' instead.
  207. */
  208. maybe_resize(lst, fd + 2);
  209. if (lst->items[fd].fd != -1) {
  210. uv_mutex_unlock(&global_epoll_lock);
  211. errno = EEXIST;
  212. return -1;
  213. }
  214. lst->items[fd].fd = fd;
  215. lst->items[fd].events = event->events;
  216. lst->items[fd].revents = 0;
  217. } else if (op == EPOLL_CTL_MOD) {
  218. if (fd >= lst->size - 1 || lst->items[fd].fd == -1) {
  219. uv_mutex_unlock(&global_epoll_lock);
  220. errno = ENOENT;
  221. return -1;
  222. }
  223. lst->items[fd].events = event->events;
  224. lst->items[fd].revents = 0;
  225. } else
  226. abort();
  227. uv_mutex_unlock(&global_epoll_lock);
  228. return 0;
  229. }
  230. #define EP_MAX_PFDS (ULONG_MAX / sizeof(struct pollfd))
  231. #define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
  232. int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
  233. int maxevents, int timeout) {
  234. nmsgsfds_t size;
  235. struct pollfd* pfds;
  236. int pollret;
  237. int reventcount;
  238. int nevents;
  239. struct pollfd msg_fd;
  240. int i;
  241. if (!lst || !lst->items || !events) {
  242. errno = EFAULT;
  243. return -1;
  244. }
  245. if (lst->size > EP_MAX_PFDS) {
  246. errno = EINVAL;
  247. return -1;
  248. }
  249. if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) {
  250. errno = EINVAL;
  251. return -1;
  252. }
  253. if (lst->size > 0)
  254. _SET_FDS_MSGS(size, 1, lst->size - 1);
  255. else
  256. _SET_FDS_MSGS(size, 0, 0);
  257. pfds = lst->items;
  258. pollret = poll(pfds, size, timeout);
  259. if (pollret <= 0)
  260. return pollret;
  261. assert(lst->size > 0);
  262. pollret = _NFDS(pollret) + _NMSGS(pollret);
  263. reventcount = 0;
  264. nevents = 0;
  265. msg_fd = pfds[lst->size - 1];
  266. for (i = 0;
  267. i < lst->size && i < maxevents && reventcount < pollret; ++i) {
  268. struct epoll_event ev;
  269. struct pollfd* pfd;
  270. pfd = &pfds[i];
  271. if (pfd->fd == -1 || pfd->revents == 0)
  272. continue;
  273. ev.fd = pfd->fd;
  274. ev.events = pfd->revents;
  275. ev.is_msg = 0;
  276. if (pfd->revents & POLLIN && pfd->revents & POLLOUT)
  277. reventcount += 2;
  278. else if (pfd->revents & (POLLIN | POLLOUT))
  279. ++reventcount;
  280. pfd->revents = 0;
  281. events[nevents++] = ev;
  282. }
  283. if (msg_fd.revents != 0 && msg_fd.fd != -1)
  284. if (i == lst->size)
  285. events[nevents - 1].is_msg = 1;
  286. return nevents;
  287. }
  288. int epoll_file_close(int fd) {
  289. QUEUE* q;
  290. uv_once(&once, epoll_init);
  291. uv_mutex_lock(&global_epoll_lock);
  292. QUEUE_FOREACH(q, &global_epoll_queue) {
  293. uv__os390_epoll* lst;
  294. lst = QUEUE_DATA(q, uv__os390_epoll, member);
  295. if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1)
  296. lst->items[fd].fd = -1;
  297. }
  298. uv_mutex_unlock(&global_epoll_lock);
  299. return 0;
  300. }
  301. void epoll_queue_close(uv__os390_epoll* lst) {
  302. /* Remove epoll instance from global queue */
  303. uv_mutex_lock(&global_epoll_lock);
  304. QUEUE_REMOVE(&lst->member);
  305. uv_mutex_unlock(&global_epoll_lock);
  306. /* Free resources */
  307. msgctl(lst->msg_queue, IPC_RMID, NULL);
  308. lst->msg_queue = -1;
  309. uv__free(lst->items);
  310. lst->items = NULL;
  311. }
  312. int nanosleep(const struct timespec* req, struct timespec* rem) {
  313. unsigned nano;
  314. unsigned seconds;
  315. unsigned events;
  316. unsigned secrem;
  317. unsigned nanorem;
  318. int rv;
  319. int err;
  320. int rsn;
  321. nano = (int)req->tv_nsec;
  322. seconds = req->tv_sec;
  323. events = CW_CONDVAR | CW_INTRPT;
  324. secrem = 0;
  325. nanorem = 0;
  326. #if defined(_LP64)
  327. BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn);
  328. #else
  329. BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn);
  330. #endif
  331. /* Don't clobber errno unless BPX1CTW/BPX4CTW errored.
  332. * Don't leak EAGAIN, that just means the timeout expired.
  333. */
  334. if (rv == -1)
  335. if (err == EAGAIN)
  336. rv = 0;
  337. else
  338. errno = err;
  339. if (rem != NULL && (rv == 0 || err == EINTR)) {
  340. rem->tv_nsec = nanorem;
  341. rem->tv_sec = secrem;
  342. }
  343. return rv;
  344. }
  345. char* mkdtemp(char* path) {
  346. static const char* tempchars =
  347. "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  348. static const size_t num_chars = 62;
  349. static const size_t num_x = 6;
  350. char *ep, *cp;
  351. unsigned int tries, i;
  352. size_t len;
  353. uint64_t v;
  354. int fd;
  355. int retval;
  356. int saved_errno;
  357. len = strlen(path);
  358. ep = path + len;
  359. if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) {
  360. errno = EINVAL;
  361. return NULL;
  362. }
  363. fd = open("/dev/urandom", O_RDONLY);
  364. if (fd == -1)
  365. return NULL;
  366. tries = TMP_MAX;
  367. retval = -1;
  368. do {
  369. if (read(fd, &v, sizeof(v)) != sizeof(v))
  370. break;
  371. cp = ep - num_x;
  372. for (i = 0; i < num_x; i++) {
  373. *cp++ = tempchars[v % num_chars];
  374. v /= num_chars;
  375. }
  376. if (mkdir(path, S_IRWXU) == 0) {
  377. retval = 0;
  378. break;
  379. }
  380. else if (errno != EEXIST)
  381. break;
  382. } while (--tries);
  383. saved_errno = errno;
  384. uv__close(fd);
  385. if (tries == 0) {
  386. errno = EEXIST;
  387. return NULL;
  388. }
  389. if (retval == -1) {
  390. errno = saved_errno;
  391. return NULL;
  392. }
  393. return path;
  394. }
  395. ssize_t os390_readlink(const char* path, char* buf, size_t len) {
  396. ssize_t rlen;
  397. ssize_t vlen;
  398. ssize_t plen;
  399. char* delimiter;
  400. char old_delim;
  401. char* tmpbuf;
  402. char realpathstr[PATH_MAX + 1];
  403. tmpbuf = uv__malloc(len + 1);
  404. if (tmpbuf == NULL) {
  405. errno = ENOMEM;
  406. return -1;
  407. }
  408. rlen = readlink(path, tmpbuf, len);
  409. if (rlen < 0) {
  410. uv__free(tmpbuf);
  411. return rlen;
  412. }
  413. if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) {
  414. /* Straightforward readlink. */
  415. memcpy(buf, tmpbuf, rlen);
  416. uv__free(tmpbuf);
  417. return rlen;
  418. }
  419. /*
  420. * There is a parmlib variable at the beginning
  421. * which needs interpretation.
  422. */
  423. tmpbuf[rlen] = '\0';
  424. delimiter = strchr(tmpbuf + 2, '/');
  425. if (delimiter == NULL)
  426. /* No slash at the end */
  427. delimiter = strchr(tmpbuf + 2, '\0');
  428. /* Read real path of the variable. */
  429. old_delim = *delimiter;
  430. *delimiter = '\0';
  431. if (realpath(tmpbuf, realpathstr) == NULL) {
  432. uv__free(tmpbuf);
  433. return -1;
  434. }
  435. /* realpathstr is not guaranteed to end with null byte.*/
  436. realpathstr[PATH_MAX] = '\0';
  437. /* Reset the delimiter and fill up the buffer. */
  438. *delimiter = old_delim;
  439. plen = strlen(delimiter);
  440. vlen = strlen(realpathstr);
  441. rlen = plen + vlen;
  442. if (rlen > len) {
  443. uv__free(tmpbuf);
  444. errno = ENAMETOOLONG;
  445. return -1;
  446. }
  447. memcpy(buf, realpathstr, vlen);
  448. memcpy(buf + vlen, delimiter, plen);
  449. /* Done using temporary buffer. */
  450. uv__free(tmpbuf);
  451. return rlen;
  452. }
  453. size_t strnlen(const char* str, size_t maxlen) {
  454. char* p = memchr(str, 0, maxlen);
  455. if (p == NULL)
  456. return maxlen;
  457. else
  458. return p - str;
  459. }
  460. int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) {
  461. UNREACHABLE();
  462. }
  463. int sem_destroy(UV_PLATFORM_SEM_T* semid) {
  464. UNREACHABLE();
  465. }
  466. int sem_post(UV_PLATFORM_SEM_T* semid) {
  467. UNREACHABLE();
  468. }
  469. int sem_trywait(UV_PLATFORM_SEM_T* semid) {
  470. UNREACHABLE();
  471. }
  472. int sem_wait(UV_PLATFORM_SEM_T* semid) {
  473. UNREACHABLE();
  474. }