Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmlibuv/src/unix/os390-syscalls.c
3156 views
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
22
23
#include "os390-syscalls.h"
24
#include <errno.h>
25
#include <stdlib.h>
26
#include <search.h>
27
#include <termios.h>
28
#include <sys/msg.h>
29
30
static QUEUE global_epoll_queue;
31
static uv_mutex_t global_epoll_lock;
32
static uv_once_t once = UV_ONCE_INIT;
33
34
int scandir(const char* maindir, struct dirent*** namelist,
35
int (*filter)(const struct dirent*),
36
int (*compar)(const struct dirent**,
37
const struct dirent **)) {
38
struct dirent** nl;
39
struct dirent** nl_copy;
40
struct dirent* dirent;
41
unsigned count;
42
size_t allocated;
43
DIR* mdir;
44
45
nl = NULL;
46
count = 0;
47
allocated = 0;
48
mdir = opendir(maindir);
49
if (!mdir)
50
return -1;
51
52
for (;;) {
53
dirent = readdir(mdir);
54
if (!dirent)
55
break;
56
if (!filter || filter(dirent)) {
57
struct dirent* copy;
58
copy = uv__malloc(sizeof(*copy));
59
if (!copy)
60
goto error;
61
memcpy(copy, dirent, sizeof(*copy));
62
63
nl_copy = uv__realloc(nl, sizeof(*copy) * (count + 1));
64
if (nl_copy == NULL) {
65
uv__free(copy);
66
goto error;
67
}
68
69
nl = nl_copy;
70
nl[count++] = copy;
71
}
72
}
73
74
qsort(nl, count, sizeof(struct dirent *),
75
(int (*)(const void *, const void *)) compar);
76
77
closedir(mdir);
78
79
*namelist = nl;
80
return count;
81
82
error:
83
while (count > 0) {
84
dirent = nl[--count];
85
uv__free(dirent);
86
}
87
uv__free(nl);
88
closedir(mdir);
89
errno = ENOMEM;
90
return -1;
91
}
92
93
94
static unsigned int next_power_of_two(unsigned int val) {
95
val -= 1;
96
val |= val >> 1;
97
val |= val >> 2;
98
val |= val >> 4;
99
val |= val >> 8;
100
val |= val >> 16;
101
val += 1;
102
return val;
103
}
104
105
106
static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
107
unsigned int newsize;
108
unsigned int i;
109
struct pollfd* newlst;
110
struct pollfd event;
111
112
if (len <= lst->size)
113
return;
114
115
if (lst->size == 0)
116
event.fd = -1;
117
else {
118
/* Extract the message queue at the end. */
119
event = lst->items[lst->size - 1];
120
lst->items[lst->size - 1].fd = -1;
121
}
122
123
newsize = next_power_of_two(len);
124
newlst = uv__reallocf(lst->items, newsize * sizeof(lst->items[0]));
125
126
if (newlst == NULL)
127
abort();
128
for (i = lst->size; i < newsize; ++i)
129
newlst[i].fd = -1;
130
131
/* Restore the message queue at the end */
132
newlst[newsize - 1] = event;
133
134
lst->items = newlst;
135
lst->size = newsize;
136
}
137
138
139
void uv__os390_cleanup(void) {
140
msgctl(uv_backend_fd(uv_default_loop()), IPC_RMID, NULL);
141
}
142
143
144
static void init_message_queue(uv__os390_epoll* lst) {
145
struct {
146
long int header;
147
char body;
148
} msg;
149
150
/* initialize message queue */
151
lst->msg_queue = msgget(IPC_PRIVATE, 0600 | IPC_CREAT);
152
if (lst->msg_queue == -1)
153
abort();
154
155
/*
156
On z/OS, the message queue will be affiliated with the process only
157
when a send is performed on it. Once this is done, the system
158
can be queried for all message queues belonging to our process id.
159
*/
160
msg.header = 1;
161
if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0)
162
abort();
163
164
/* Clean up the dummy message sent above */
165
if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body))
166
abort();
167
}
168
169
170
static void before_fork(void) {
171
uv_mutex_lock(&global_epoll_lock);
172
}
173
174
175
static void after_fork(void) {
176
uv_mutex_unlock(&global_epoll_lock);
177
}
178
179
180
static void child_fork(void) {
181
QUEUE* q;
182
uv_once_t child_once = UV_ONCE_INIT;
183
184
/* reset once */
185
memcpy(&once, &child_once, sizeof(child_once));
186
187
/* reset epoll list */
188
while (!QUEUE_EMPTY(&global_epoll_queue)) {
189
uv__os390_epoll* lst;
190
q = QUEUE_HEAD(&global_epoll_queue);
191
QUEUE_REMOVE(q);
192
lst = QUEUE_DATA(q, uv__os390_epoll, member);
193
uv__free(lst->items);
194
lst->items = NULL;
195
lst->size = 0;
196
}
197
198
uv_mutex_unlock(&global_epoll_lock);
199
uv_mutex_destroy(&global_epoll_lock);
200
}
201
202
203
static void epoll_init(void) {
204
QUEUE_INIT(&global_epoll_queue);
205
if (uv_mutex_init(&global_epoll_lock))
206
abort();
207
208
if (pthread_atfork(&before_fork, &after_fork, &child_fork))
209
abort();
210
}
211
212
213
uv__os390_epoll* epoll_create1(int flags) {
214
uv__os390_epoll* lst;
215
216
lst = uv__malloc(sizeof(*lst));
217
if (lst != NULL) {
218
/* initialize list */
219
lst->size = 0;
220
lst->items = NULL;
221
init_message_queue(lst);
222
maybe_resize(lst, 1);
223
lst->items[lst->size - 1].fd = lst->msg_queue;
224
lst->items[lst->size - 1].events = POLLIN;
225
lst->items[lst->size - 1].revents = 0;
226
uv_once(&once, epoll_init);
227
uv_mutex_lock(&global_epoll_lock);
228
QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
229
uv_mutex_unlock(&global_epoll_lock);
230
}
231
232
return lst;
233
}
234
235
236
int epoll_ctl(uv__os390_epoll* lst,
237
int op,
238
int fd,
239
struct epoll_event *event) {
240
uv_mutex_lock(&global_epoll_lock);
241
242
if (op == EPOLL_CTL_DEL) {
243
if (fd >= lst->size || lst->items[fd].fd == -1) {
244
uv_mutex_unlock(&global_epoll_lock);
245
errno = ENOENT;
246
return -1;
247
}
248
lst->items[fd].fd = -1;
249
} else if (op == EPOLL_CTL_ADD) {
250
251
/* Resizing to 'fd + 1' would expand the list to contain at least
252
* 'fd'. But we need to guarantee that the last index on the list
253
* is reserved for the message queue. So specify 'fd + 2' instead.
254
*/
255
maybe_resize(lst, fd + 2);
256
if (lst->items[fd].fd != -1) {
257
uv_mutex_unlock(&global_epoll_lock);
258
errno = EEXIST;
259
return -1;
260
}
261
lst->items[fd].fd = fd;
262
lst->items[fd].events = event->events;
263
lst->items[fd].revents = 0;
264
} else if (op == EPOLL_CTL_MOD) {
265
if (fd >= lst->size - 1 || lst->items[fd].fd == -1) {
266
uv_mutex_unlock(&global_epoll_lock);
267
errno = ENOENT;
268
return -1;
269
}
270
lst->items[fd].events = event->events;
271
lst->items[fd].revents = 0;
272
} else
273
abort();
274
275
uv_mutex_unlock(&global_epoll_lock);
276
return 0;
277
}
278
279
#define EP_MAX_PFDS (ULONG_MAX / sizeof(struct pollfd))
280
#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
281
282
int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
283
int maxevents, int timeout) {
284
nmsgsfds_t size;
285
struct pollfd* pfds;
286
int pollret;
287
int pollfdret;
288
int pollmsgret;
289
int reventcount;
290
int nevents;
291
struct pollfd msg_fd;
292
int i;
293
294
if (!lst || !lst->items || !events) {
295
errno = EFAULT;
296
return -1;
297
}
298
299
if (lst->size > EP_MAX_PFDS) {
300
errno = EINVAL;
301
return -1;
302
}
303
304
if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) {
305
errno = EINVAL;
306
return -1;
307
}
308
309
assert(lst->size > 0);
310
_SET_FDS_MSGS(size, 1, lst->size - 1);
311
pfds = lst->items;
312
pollret = poll(pfds, size, timeout);
313
if (pollret <= 0)
314
return pollret;
315
316
pollfdret = _NFDS(pollret);
317
pollmsgret = _NMSGS(pollret);
318
319
reventcount = 0;
320
nevents = 0;
321
msg_fd = pfds[lst->size - 1]; /* message queue is always last entry */
322
maxevents = maxevents - pollmsgret; /* allow spot for message queue */
323
for (i = 0;
324
i < lst->size - 1 &&
325
nevents < maxevents &&
326
reventcount < pollfdret; ++i) {
327
struct epoll_event ev;
328
struct pollfd* pfd;
329
330
pfd = &pfds[i];
331
if (pfd->fd == -1 || pfd->revents == 0)
332
continue;
333
334
ev.fd = pfd->fd;
335
ev.events = pfd->revents;
336
ev.is_msg = 0;
337
338
reventcount++;
339
events[nevents++] = ev;
340
}
341
342
if (pollmsgret > 0 && msg_fd.revents != 0 && msg_fd.fd != -1) {
343
struct epoll_event ev;
344
ev.fd = msg_fd.fd;
345
ev.events = msg_fd.revents;
346
ev.is_msg = 1;
347
events[nevents++] = ev;
348
}
349
350
return nevents;
351
}
352
353
354
int epoll_file_close(int fd) {
355
QUEUE* q;
356
357
uv_once(&once, epoll_init);
358
uv_mutex_lock(&global_epoll_lock);
359
QUEUE_FOREACH(q, &global_epoll_queue) {
360
uv__os390_epoll* lst;
361
362
lst = QUEUE_DATA(q, uv__os390_epoll, member);
363
if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1)
364
lst->items[fd].fd = -1;
365
}
366
367
uv_mutex_unlock(&global_epoll_lock);
368
return 0;
369
}
370
371
void epoll_queue_close(uv__os390_epoll* lst) {
372
/* Remove epoll instance from global queue */
373
uv_mutex_lock(&global_epoll_lock);
374
QUEUE_REMOVE(&lst->member);
375
uv_mutex_unlock(&global_epoll_lock);
376
377
/* Free resources */
378
msgctl(lst->msg_queue, IPC_RMID, NULL);
379
lst->msg_queue = -1;
380
uv__free(lst->items);
381
lst->items = NULL;
382
}
383
384
385
char* mkdtemp(char* path) {
386
static const char* tempchars =
387
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
388
static const size_t num_chars = 62;
389
static const size_t num_x = 6;
390
char *ep, *cp;
391
unsigned int tries, i;
392
size_t len;
393
uint64_t v;
394
int fd;
395
int retval;
396
int saved_errno;
397
398
len = strlen(path);
399
ep = path + len;
400
if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) {
401
errno = EINVAL;
402
return NULL;
403
}
404
405
fd = open("/dev/urandom", O_RDONLY);
406
if (fd == -1)
407
return NULL;
408
409
tries = TMP_MAX;
410
retval = -1;
411
do {
412
if (read(fd, &v, sizeof(v)) != sizeof(v))
413
break;
414
415
cp = ep - num_x;
416
for (i = 0; i < num_x; i++) {
417
*cp++ = tempchars[v % num_chars];
418
v /= num_chars;
419
}
420
421
if (mkdir(path, S_IRWXU) == 0) {
422
retval = 0;
423
break;
424
}
425
else if (errno != EEXIST)
426
break;
427
} while (--tries);
428
429
saved_errno = errno;
430
uv__close(fd);
431
if (tries == 0) {
432
errno = EEXIST;
433
return NULL;
434
}
435
436
if (retval == -1) {
437
errno = saved_errno;
438
return NULL;
439
}
440
441
return path;
442
}
443
444
445
ssize_t os390_readlink(const char* path, char* buf, size_t len) {
446
ssize_t rlen;
447
ssize_t vlen;
448
ssize_t plen;
449
char* delimiter;
450
char old_delim;
451
char* tmpbuf;
452
char realpathstr[PATH_MAX + 1];
453
454
tmpbuf = uv__malloc(len + 1);
455
if (tmpbuf == NULL) {
456
errno = ENOMEM;
457
return -1;
458
}
459
460
rlen = readlink(path, tmpbuf, len);
461
if (rlen < 0) {
462
uv__free(tmpbuf);
463
return rlen;
464
}
465
466
if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) {
467
/* Straightforward readlink. */
468
memcpy(buf, tmpbuf, rlen);
469
uv__free(tmpbuf);
470
return rlen;
471
}
472
473
/*
474
* There is a parmlib variable at the beginning
475
* which needs interpretation.
476
*/
477
tmpbuf[rlen] = '\0';
478
delimiter = strchr(tmpbuf + 2, '/');
479
if (delimiter == NULL)
480
/* No slash at the end */
481
delimiter = strchr(tmpbuf + 2, '\0');
482
483
/* Read real path of the variable. */
484
old_delim = *delimiter;
485
*delimiter = '\0';
486
if (realpath(tmpbuf, realpathstr) == NULL) {
487
uv__free(tmpbuf);
488
return -1;
489
}
490
491
/* realpathstr is not guaranteed to end with null byte.*/
492
realpathstr[PATH_MAX] = '\0';
493
494
/* Reset the delimiter and fill up the buffer. */
495
*delimiter = old_delim;
496
plen = strlen(delimiter);
497
vlen = strlen(realpathstr);
498
rlen = plen + vlen;
499
if (rlen > len) {
500
uv__free(tmpbuf);
501
errno = ENAMETOOLONG;
502
return -1;
503
}
504
memcpy(buf, realpathstr, vlen);
505
memcpy(buf + vlen, delimiter, plen);
506
507
/* Done using temporary buffer. */
508
uv__free(tmpbuf);
509
510
return rlen;
511
}
512
513
514
int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) {
515
UNREACHABLE();
516
}
517
518
519
int sem_destroy(UV_PLATFORM_SEM_T* semid) {
520
UNREACHABLE();
521
}
522
523
524
int sem_post(UV_PLATFORM_SEM_T* semid) {
525
UNREACHABLE();
526
}
527
528
529
int sem_trywait(UV_PLATFORM_SEM_T* semid) {
530
UNREACHABLE();
531
}
532
533
534
int sem_wait(UV_PLATFORM_SEM_T* semid) {
535
UNREACHABLE();
536
}
537
538