ia64/xen-unstable

view extras/mini-os/lib/sys.c @ 17042:a905c582a406

Add stubdomain support. See stubdom/README for usage details.

- Move PAGE_SIZE and STACK_SIZE into __PAGE_SIZE and __STACK_SIZE in
arch_limits.h so as to permit getting them from there without
pulling all the internal Mini-OS defines.
- Setup a xen-elf cross-compilation environment in stubdom/cross-root
- Add a POSIX layer on top of Mini-OS by linking against the newlib C
library and lwIP, and implementing the Unixish part in mini-os/lib/sys.c
- Cross-compile zlib and libpci too.
- Add an xs.h-compatible layer on top of Mini-OS' xenbus.
- Cross-compile libxc with an additional xc_minios.c and a few things
disabled.
- Cross-compile ioemu with an additional block-vbd, but without sound,
tpm and other details. A few hacks are needed:
- Align ide and scsi buffers at least on sector size to permit
direct transmission to the block backend. While we are at it, just
page-align it to possibly save a segment. Also, limit the scsi
buffer size because of limitations of the block paravirtualization
protocol.
- Allocate big tables dynamically rather that letting them go to
bss: when Mini-OS gets installed in memory, bss is not lazily
allocated, and doing so during Mini-OS is unnecessarily trick while
we can simply use malloc.
- Had to change the Mini-OS compilation somehow, so as to export
Mini-OS compilation flags to the Makefiles of libxc and ioemu.

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Feb 12 14:35:39 2008 +0000 (2008-02-12)
parents
children 580bcd4c9642
line source
1 /*
2 * POSIX-compatible libc layer
3 *
4 * Samuel Thibault <Samuel.Thibault@eu.citrix.net>, October 2007
5 *
6 * Provides the UNIXish part of the standard libc function.
7 *
8 * Relatively straight-forward: just multiplex the file descriptor operations
9 * among the various file types (console, FS, network, ...)
10 */
12 //#define LIBC_VERBOSE
13 //#define LIBC_DEBUG
15 #ifdef LIBC_DEBUG
16 #define DEBUG(fmt,...) printk(fmt, ##__VA_ARGS__)
17 #else
18 #define DEBUG(fmt,...)
19 #endif
21 #ifdef HAVE_LIBC
22 #include <os.h>
23 #include <console.h>
24 #include <sched.h>
25 #include <events.h>
26 #include <wait.h>
27 #include <netfront.h>
28 #include <blkfront.h>
29 #include <xenbus.h>
30 #include <xs.h>
32 #include <sys/types.h>
33 #include <sys/unistd.h>
34 #include <sys/stat.h>
35 #include <sys/mman.h>
36 #include <time.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <pthread.h>
40 #include <assert.h>
41 #include <dirent.h>
42 #include <stdlib.h>
43 #include <math.h>
45 #include <lwip/sockets.h>
46 #include <fs.h>
48 #define debug(fmt, ...) \
50 #define print_unsupported(fmt, ...) \
51 printk("Unsupported function "fmt" called in Mini-OS kernel\n", ## __VA_ARGS__);
53 /* Crash on function call */
54 #define unsupported_function_crash(function) \
55 int __unsup_##function(void) asm(#function); \
56 int __unsup_##function(void) \
57 { \
58 print_unsupported(#function); \
59 do_exit(); \
60 }
62 /* Log and err out on function call */
63 #define unsupported_function_log(type, function, ret) \
64 type __unsup_##function(void) asm(#function); \
65 type __unsup_##function(void) \
66 { \
67 print_unsupported(#function); \
68 errno = ENOSYS; \
69 return ret; \
70 }
72 /* Err out on function call */
73 #define unsupported_function(type, function, ret) \
74 type __unsup_##function(void) asm(#function); \
75 type __unsup_##function(void) \
76 { \
77 errno = ENOSYS; \
78 return ret; \
79 }
81 #define NOFILE 32
82 extern int xc_evtchn_close(int fd);
84 pthread_mutex_t fd_lock = PTHREAD_MUTEX_INITIALIZER;
85 struct file files[NOFILE] = {
86 { .type = FTYPE_CONSOLE }, /* stdin */
87 { .type = FTYPE_CONSOLE }, /* stdout */
88 { .type = FTYPE_CONSOLE }, /* stderr */
89 };
91 DECLARE_WAIT_QUEUE_HEAD(event_queue);
93 int alloc_fd(enum fd_type type)
94 {
95 int i;
96 pthread_mutex_lock(&fd_lock);
97 for (i=0; i<NOFILE; i++) {
98 if (files[i].type == FTYPE_NONE) {
99 files[i].type = type;
100 pthread_mutex_unlock(&fd_lock);
101 return i;
102 }
103 }
104 pthread_mutex_unlock(&fd_lock);
105 printk("Too many opened files\n");
106 do_exit();
107 }
109 void close_all_files(void)
110 {
111 int i;
112 pthread_mutex_lock(&fd_lock);
113 for (i=NOFILE - 1; i > 0; i--)
114 if (files[i].type != FTYPE_NONE)
115 close(i);
116 pthread_mutex_unlock(&fd_lock);
117 }
119 int dup2(int oldfd, int newfd)
120 {
121 pthread_mutex_lock(&fd_lock);
122 if (files[newfd].type != FTYPE_NONE)
123 close(newfd);
124 // XXX: this is a bit bogus, as we are supposed to share the offset etc
125 files[newfd] = files[oldfd];
126 pthread_mutex_unlock(&fd_lock);
127 return 0;
128 }
130 pid_t getpid(void)
131 {
132 return 1;
133 }
135 pid_t getppid(void)
136 {
137 return 1;
138 }
140 pid_t setsid(void)
141 {
142 return 1;
143 }
145 char *getcwd(char *buf, size_t size)
146 {
147 snprintf(buf, size, "/");
148 return buf;
149 }
151 #define LOG_PATH "/var/log/"
153 int mkdir(const char *pathname, mode_t mode)
154 {
155 int ret;
156 ret = fs_create(fs_import, (char *) pathname, 1, mode);
157 if (ret < 0) {
158 errno = EIO;
159 return -1;
160 }
161 return 0;
162 }
164 int open(const char *pathname, int flags, ...)
165 {
166 int fs_fd, fd;
167 /* Ugly, but fine. */
168 if (!strncmp(pathname,LOG_PATH,strlen(LOG_PATH))) {
169 fd = alloc_fd(FTYPE_CONSOLE);
170 printk("open(%s) -> %d\n", pathname, fd);
171 return fd;
172 }
173 printk("open(%s)", pathname);
174 fs_fd = fs_open(fs_import, (void *) pathname);
175 if (fs_fd < 0) {
176 errno = EIO;
177 return -1;
178 }
179 fd = alloc_fd(FTYPE_FILE);
180 printk("-> %d\n", fd);
181 files[fd].file.fd = fs_fd;
182 files[fd].file.offset = 0;
183 return fd;
184 }
185 #if defined(__x86_64__) || defined(__ia64__)
186 __typeof__(open) open64 __attribute__((__alias__("open")));
187 #endif
189 int isatty(int fd)
190 {
191 return files[fd].type == FTYPE_CONSOLE;
192 }
194 int read(int fd, void *buf, size_t nbytes)
195 {
196 switch (files[fd].type) {
197 case FTYPE_CONSOLE:
198 return 0;
199 case FTYPE_FILE: {
200 ssize_t ret;
201 if (nbytes > PAGE_SIZE)
202 nbytes = PAGE_SIZE;
203 ret = fs_read(fs_import, files[fd].file.fd, buf, nbytes, files[fd].file.offset);
204 if (ret > 0) {
205 files[fd].file.offset += ret;
206 return ret;
207 } else if (ret < 0) {
208 errno = EIO;
209 return -1;
210 }
211 return 0;
212 }
213 case FTYPE_SOCKET:
214 return lwip_read(files[fd].socket.fd, buf, nbytes);
215 case FTYPE_TAP: {
216 ssize_t ret;
217 ret = netfront_receive(files[fd].tap.dev, buf, nbytes);
218 if (ret <= 0) {
219 errno = EAGAIN;
220 return -1;
221 }
222 return ret;
223 }
224 case FTYPE_NONE:
225 case FTYPE_XENBUS:
226 case FTYPE_EVTCHN:
227 case FTYPE_BLK:
228 break;
229 }
230 printk("read(%d): Bad descriptor\n", fd);
231 errno = EBADF;
232 return -1;
233 }
235 int write(int fd, const void *buf, size_t nbytes)
236 {
237 switch (files[fd].type) {
238 case FTYPE_CONSOLE:
239 console_print((char *)buf, nbytes);
240 return nbytes;
241 case FTYPE_FILE: {
242 ssize_t ret;
243 if (nbytes > PAGE_SIZE)
244 nbytes = PAGE_SIZE;
245 ret = fs_write(fs_import, files[fd].file.fd, (void *) buf, nbytes, files[fd].file.offset);
246 if (ret > 0) {
247 files[fd].file.offset += ret;
248 return ret;
249 } else if (ret < 0) {
250 errno = EIO;
251 return -1;
252 }
253 return 0;
254 }
255 case FTYPE_SOCKET:
256 return lwip_write(files[fd].socket.fd, (void*) buf, nbytes);
257 case FTYPE_TAP:
258 netfront_xmit(files[fd].tap.dev, (void*) buf, nbytes);
259 return nbytes;
260 case FTYPE_NONE:
261 case FTYPE_XENBUS:
262 case FTYPE_EVTCHN:
263 case FTYPE_BLK:
264 break;
265 }
266 printk("write(%d): Bad descriptor\n", fd);
267 errno = EBADF;
268 return -1;
269 }
271 off_t lseek(int fd, off_t offset, int whence)
272 {
273 if (files[fd].type != FTYPE_FILE) {
274 errno = ESPIPE;
275 return (off_t) -1;
276 }
277 switch (whence) {
278 case SEEK_SET:
279 files[fd].file.offset = offset;
280 break;
281 case SEEK_CUR:
282 files[fd].file.offset += offset;
283 break;
284 case SEEK_END: {
285 struct stat st;
286 int ret;
287 ret = fstat(fd, &st);
288 if (ret)
289 return -1;
290 files[fd].file.offset = st.st_size + offset;
291 break;
292 }
293 default:
294 errno = EINVAL;
295 return -1;
296 }
297 return files[fd].file.offset;
298 }
299 #if defined(__x86_64__) || defined(__ia64__)
300 __typeof__(lseek) lseek64 __attribute__((__alias__("lseek")));
301 #endif
303 int fsync(int fd) {
304 switch (files[fd].type) {
305 case FTYPE_FILE: {
306 int ret;
307 ret = fs_sync(fs_import, files[fd].file.fd);
308 if (ret < 0) {
309 errno = EIO;
310 return -1;
311 }
312 return 0;
313 }
314 case FTYPE_NONE:
315 case FTYPE_CONSOLE:
316 case FTYPE_SOCKET:
317 case FTYPE_XENBUS:
318 case FTYPE_EVTCHN:
319 case FTYPE_TAP:
320 case FTYPE_BLK:
321 break;
322 }
323 printk("fsync(%d): Bad descriptor\n", fd);
324 errno = EBADF;
325 return -1;
326 }
328 int close(int fd)
329 {
330 printk("close(%d)\n", fd);
331 switch (files[fd].type) {
332 case FTYPE_CONSOLE:
333 files[fd].type = FTYPE_NONE;
334 return 0;
335 case FTYPE_FILE: {
336 int ret = fs_close(fs_import, files[fd].file.fd);
337 files[fd].type = FTYPE_NONE;
338 if (ret < 0) {
339 errno = EIO;
340 return -1;
341 }
342 return 0;
343 }
344 case FTYPE_XENBUS:
345 xs_daemon_close((void*)(intptr_t) fd);
346 return 0;
347 case FTYPE_SOCKET: {
348 int res = lwip_close(files[fd].socket.fd);
349 files[fd].type = FTYPE_NONE;
350 return res;
351 }
352 case FTYPE_EVTCHN:
353 xc_evtchn_close(fd);
354 return 0;
355 case FTYPE_TAP:
356 shutdown_netfront(files[fd].tap.dev);
357 files[fd].type = FTYPE_NONE;
358 return 0;
359 case FTYPE_BLK:
360 shutdown_blkfront(files[fd].blk.dev);
361 files[fd].type = FTYPE_NONE;
362 return 0;
363 case FTYPE_NONE:
364 break;
365 }
366 printk("close(%d): Bad descriptor\n", fd);
367 errno = EBADF;
368 return -1;
369 }
371 static void init_stat(struct stat *buf)
372 {
373 memset(buf, 0, sizeof(*buf));
374 buf->st_dev = 0;
375 buf->st_ino = 0;
376 buf->st_nlink = 1;
377 buf->st_rdev = 0;
378 buf->st_blksize = 4096;
379 buf->st_blocks = 0;
380 }
382 static void stat_from_fs(struct stat *buf, struct fsif_stat_response *stat)
383 {
384 buf->st_mode = stat->stat_mode;
385 buf->st_uid = stat->stat_uid;
386 buf->st_gid = stat->stat_gid;
387 buf->st_size = stat->stat_size;
388 buf->st_atime = stat->stat_atime;
389 buf->st_mtime = stat->stat_mtime;
390 buf->st_ctime = stat->stat_ctime;
391 }
393 int stat(const char *path, struct stat *buf)
394 {
395 struct fsif_stat_response stat;
396 int ret;
397 int fs_fd;
398 printk("stat(%s)\n", path);
399 fs_fd = fs_open(fs_import, (char*) path);
400 if (fs_fd < 0) {
401 errno = EIO;
402 ret = -1;
403 goto out;
404 }
405 ret = fs_stat(fs_import, fs_fd, &stat);
406 if (ret < 0) {
407 errno = EIO;
408 ret = -1;
409 goto outfd;
410 }
411 init_stat(buf);
412 stat_from_fs(buf, &stat);
413 ret = 0;
415 outfd:
416 fs_close(fs_import, fs_fd);
417 out:
418 return ret;
419 }
421 int fstat(int fd, struct stat *buf)
422 {
423 init_stat(buf);
424 switch (files[fd].type) {
425 case FTYPE_CONSOLE:
426 case FTYPE_SOCKET: {
427 buf->st_mode = (files[fd].type == FTYPE_CONSOLE?S_IFCHR:S_IFSOCK) | S_IRUSR|S_IWUSR;
428 buf->st_uid = 0;
429 buf->st_gid = 0;
430 buf->st_size = 0;
431 buf->st_atime =
432 buf->st_mtime =
433 buf->st_ctime = time(NULL);
434 return 0;
435 }
436 case FTYPE_FILE: {
437 struct fsif_stat_response stat;
438 int ret;
439 ret = fs_stat(fs_import, files[fd].file.fd, &stat);
440 if (ret < 0) {
441 errno = EIO;
442 return -1;
443 }
444 /* The protocol is a bit evasive about this value */
445 stat_from_fs(buf, &stat);
446 return 0;
447 }
448 case FTYPE_NONE:
449 case FTYPE_XENBUS:
450 case FTYPE_EVTCHN:
451 case FTYPE_TAP:
452 case FTYPE_BLK:
453 break;
454 }
456 printk("statf(%d): Bad descriptor\n", fd);
457 errno = EBADF;
458 return -1;
459 }
461 int ftruncate(int fd, off_t length)
462 {
463 switch (files[fd].type) {
464 case FTYPE_FILE: {
465 int ret;
466 ret = fs_truncate(fs_import, files[fd].file.fd, length);
467 if (ret < 0) {
468 errno = EIO;
469 return -1;
470 }
471 return 0;
472 }
473 case FTYPE_NONE:
474 case FTYPE_CONSOLE:
475 case FTYPE_SOCKET:
476 case FTYPE_XENBUS:
477 case FTYPE_EVTCHN:
478 case FTYPE_TAP:
479 case FTYPE_BLK:
480 break;
481 }
483 printk("ftruncate(%d): Bad descriptor\n", fd);
484 errno = EBADF;
485 return -1;
486 }
488 int remove(const char *pathname)
489 {
490 int ret;
491 printk("remove(%s)", pathname);
492 ret = fs_remove(fs_import, (char*) pathname);
493 if (ret < 0) {
494 errno = EIO;
495 return -1;
496 }
497 return 0;
498 }
500 int unlink(const char *pathname)
501 {
502 return remove(pathname);
503 }
505 int rmdir(const char *pathname)
506 {
507 return remove(pathname);
508 }
510 int fcntl(int fd, int cmd, ...)
511 {
512 long arg;
513 va_list ap;
514 va_start(ap, cmd);
515 arg = va_arg(ap, long);
516 va_end(ap);
518 switch (cmd) {
519 case F_SETFL:
520 if (files[fd].type == FTYPE_SOCKET && !(arg & ~O_NONBLOCK)) {
521 /* Only flag supported: non-blocking mode */
522 uint32_t nblock = !!(arg & O_NONBLOCK);
523 return lwip_ioctl(files[fd].socket.fd, FIONBIO, &nblock);
524 }
525 /* Fallthrough */
526 default:
527 printk("fcntl(%d, %d, %lx/%lo)\n", fd, cmd, arg, arg);
528 errno = ENOSYS;
529 return -1;
530 }
531 }
533 DIR *opendir(const char *name)
534 {
535 DIR *ret;
536 ret = malloc(sizeof(*ret));
537 ret->name = strdup(name);
538 ret->offset = 0;
539 ret->entries = NULL;
540 ret->curentry = -1;
541 ret->nbentries = 0;
542 ret->has_more = 1;
543 return ret;
544 }
546 struct dirent *readdir(DIR *dir)
547 {
548 if (dir->curentry >= 0) {
549 free(dir->entries[dir->curentry]);
550 dir->entries[dir->curentry] = NULL;
551 }
552 dir->curentry++;
553 if (dir->curentry >= dir->nbentries) {
554 dir->offset += dir->nbentries;
555 free(dir->entries);
556 dir->curentry = -1;
557 dir->nbentries = 0;
558 if (!dir->has_more)
559 return NULL;
560 dir->entries = fs_list(fs_import, dir->name, dir->offset, &dir->nbentries, &dir->has_more);
561 if (!dir->entries || !dir->nbentries)
562 return NULL;
563 dir->curentry = 0;
564 }
565 dir->dirent.d_name = dir->entries[dir->curentry];
566 return &dir->dirent;
567 }
568 int closedir(DIR *dir)
569 {
570 int i;
571 for (i=0; i<dir->nbentries; i++)
572 free(dir->entries[i]);
573 free(dir->entries);
574 free(dir->name);
575 free(dir);
576 return 0;
577 }
579 /* We assume that only the main thread calls select(). */
581 static const char file_types[] = {
582 [FTYPE_NONE] = 'N',
583 [FTYPE_CONSOLE] = 'C',
584 [FTYPE_FILE] = 'F',
585 [FTYPE_XENBUS] = 'X',
586 [FTYPE_EVTCHN] = 'E',
587 [FTYPE_SOCKET] = 'S',
588 [FTYPE_TAP] = 'T',
589 [FTYPE_BLK] = 'B',
590 };
591 #ifdef LIBC_DEBUG
592 static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
593 {
594 int i, comma;
595 #define printfds(set) do {\
596 comma = 0; \
597 for (i = 0; i < nfds; i++) { \
598 if (FD_ISSET(i, set)) { \
599 if (comma) \
600 printk(", "); \
601 printk("%d(%c)", i, file_types[files[i].type]); \
602 comma = 1; \
603 } \
604 } \
605 } while (0)
607 printk("[");
608 if (readfds)
609 printfds(readfds);
610 printk("], [");
611 if (writefds)
612 printfds(writefds);
613 printk("], [");
614 if (exceptfds)
615 printfds(exceptfds);
616 printk("], ");
617 if (timeout)
618 printk("{ %ld, %ld }", timeout->tv_sec, timeout->tv_usec);
619 }
620 #else
621 #define dump_set(nfds, readfds, writefds, exceptfds, timeout)
622 #endif
624 /* Just poll without blocking */
625 static int select_poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
626 {
627 int i, n = 0, sock_n, sock_nfds = 0;
628 fd_set sock_readfds, sock_writefds, sock_exceptfds;
629 struct timeval timeout = { .tv_sec = 0, .tv_usec = 0};
631 #ifdef LIBC_VERBOSE
632 static int nb;
633 static int nbread[NOFILE], nbwrite[NOFILE], nbexcept[NOFILE];
634 static s64_t lastshown;
636 nb++;
637 #endif
639 /* first poll network */
640 FD_ZERO(&sock_readfds);
641 FD_ZERO(&sock_writefds);
642 FD_ZERO(&sock_exceptfds);
643 for (i = 0; i < nfds; i++) {
644 if (files[i].type == FTYPE_SOCKET) {
645 if (FD_ISSET(i, readfds)) {
646 FD_SET(files[i].socket.fd, &sock_readfds);
647 sock_nfds = i+1;
648 }
649 if (FD_ISSET(i, writefds)) {
650 FD_SET(files[i].socket.fd, &sock_writefds);
651 sock_nfds = i+1;
652 }
653 if (FD_ISSET(i, exceptfds)) {
654 FD_SET(files[i].socket.fd, &sock_exceptfds);
655 sock_nfds = i+1;
656 }
657 }
658 }
659 DEBUG("lwip_select(");
660 dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
661 DEBUG("); -> ");
662 sock_n = lwip_select(sock_nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
663 dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
664 DEBUG("\n");
666 /* Then see others as well. */
667 for (i = 0; i < nfds; i++) {
668 switch(files[i].type) {
669 case FTYPE_NONE:
670 if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds))
671 printk("bogus fd %d in select\n", i);
672 /* Fallthrough. */
673 case FTYPE_FILE:
674 FD_CLR(i, readfds);
675 FD_CLR(i, writefds);
676 FD_CLR(i, exceptfds);
677 break;
678 case FTYPE_CONSOLE:
679 FD_CLR(i, readfds);
680 if (FD_ISSET(i, writefds))
681 n++;
682 FD_CLR(i, exceptfds);
683 break;
684 case FTYPE_XENBUS:
685 if (FD_ISSET(i, readfds)) {
686 if (files[i].xenbus.events)
687 n++;
688 else
689 FD_CLR(i, readfds);
690 }
691 FD_CLR(i, writefds);
692 FD_CLR(i, exceptfds);
693 break;
694 case FTYPE_EVTCHN:
695 case FTYPE_TAP:
696 case FTYPE_BLK:
697 if (FD_ISSET(i, readfds)) {
698 if (files[i].read)
699 n++;
700 else
701 FD_CLR(i, readfds);
702 }
703 FD_CLR(i, writefds);
704 FD_CLR(i, exceptfds);
705 break;
706 case FTYPE_SOCKET:
707 if (FD_ISSET(i, readfds)) {
708 /* Optimize no-network-packet case. */
709 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_readfds))
710 n++;
711 else
712 FD_CLR(i, readfds);
713 }
714 if (FD_ISSET(i, writefds)) {
715 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_writefds))
716 n++;
717 else
718 FD_CLR(i, writefds);
719 }
720 if (FD_ISSET(i, exceptfds)) {
721 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_exceptfds))
722 n++;
723 else
724 FD_CLR(i, exceptfds);
725 }
726 break;
727 }
728 #ifdef LIBC_VERBOSE
729 if (FD_ISSET(i, readfds))
730 nbread[i]++;
731 if (FD_ISSET(i, writefds))
732 nbwrite[i]++;
733 if (FD_ISSET(i, exceptfds))
734 nbexcept[i]++;
735 #endif
736 }
737 #ifdef LIBC_VERBOSE
738 if (NOW() > lastshown + 1000000000ull) {
739 lastshown = NOW();
740 printk("%lu MB free, ", num_free_pages() / ((1 << 20) / PAGE_SIZE));
741 printk("%d(%d): ", nb, sock_n);
742 for (i = 0; i < nfds; i++) {
743 if (nbread[i] || nbwrite[i] || nbexcept[i])
744 printk(" %d(%c):", i, file_types[files[i].type]);
745 if (nbread[i])
746 printk(" %dR", nbread[i]);
747 if (nbwrite[i])
748 printk(" %dW", nbwrite[i]);
749 if (nbexcept[i])
750 printk(" %dE", nbexcept[i]);
751 }
752 printk("\n");
753 memset(nbread, 0, sizeof(nbread));
754 memset(nbwrite, 0, sizeof(nbwrite));
755 memset(nbexcept, 0, sizeof(nbexcept));
756 nb = 0;
757 }
758 #endif
759 return n;
760 }
762 /* The strategy is to
763 * - announce that we will maybe sleep
764 * - poll a bit ; if successful, return
765 * - if timeout, return
766 * - really sleep (except if somebody woke us in the meanwhile) */
767 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
768 struct timeval *timeout)
769 {
770 int n, ret;
771 fd_set myread, mywrite, myexcept;
772 struct thread *thread = get_current();
773 s_time_t start = NOW(), stop;
774 DEFINE_WAIT(w1);
775 DEFINE_WAIT(w2);
776 DEFINE_WAIT(w3);
777 DEFINE_WAIT(w4);
779 assert(thread == main_thread);
781 DEBUG("select(%d, ", nfds);
782 dump_set(nfds, readfds, writefds, exceptfds, timeout);
783 DEBUG(");\n");
785 if (timeout)
786 stop = start + SECONDS(timeout->tv_sec) + timeout->tv_usec * 1000;
787 else
788 /* just make gcc happy */
789 stop = start;
791 /* Tell people we're going to sleep before looking at what they are
792 * saying, hence letting them wake us if events happen between here and
793 * schedule() */
794 add_waiter(w1, netfront_queue);
795 add_waiter(w2, event_queue);
796 add_waiter(w3, blkfront_queue);
797 add_waiter(w4, xenbus_watch_queue);
799 myread = *readfds;
800 mywrite = *writefds;
801 myexcept = *exceptfds;
802 DEBUG("polling ");
803 dump_set(nfds, &myread, &mywrite, &myexcept, timeout);
804 DEBUG("\n");
805 n = select_poll(nfds, &myread, &mywrite, &myexcept);
807 if (n) {
808 dump_set(nfds, readfds, writefds, exceptfds, timeout);
809 if (readfds)
810 *readfds = myread;
811 if (writefds)
812 *writefds = mywrite;
813 if (exceptfds)
814 *exceptfds = myexcept;
815 DEBUG(" -> ");
816 dump_set(nfds, readfds, writefds, exceptfds, timeout);
817 DEBUG("\n");
818 wake(thread);
819 ret = n;
820 goto out;
821 }
822 if (timeout && NOW() >= stop) {
823 if (readfds)
824 FD_ZERO(readfds);
825 if (writefds)
826 FD_ZERO(writefds);
827 if (exceptfds)
828 FD_ZERO(exceptfds);
829 timeout->tv_sec = 0;
830 timeout->tv_usec = 0;
831 wake(thread);
832 ret = 0;
833 goto out;
834 }
836 if (timeout)
837 thread->wakeup_time = stop;
838 schedule();
840 myread = *readfds;
841 mywrite = *writefds;
842 myexcept = *exceptfds;
843 n = select_poll(nfds, &myread, &mywrite, &myexcept);
845 if (n) {
846 if (readfds)
847 *readfds = myread;
848 if (writefds)
849 *writefds = mywrite;
850 if (exceptfds)
851 *exceptfds = myexcept;
852 ret = n;
853 goto out;
854 }
855 errno = EINTR;
856 ret = -1;
858 out:
859 remove_waiter(w1);
860 remove_waiter(w2);
861 remove_waiter(w3);
862 remove_waiter(w4);
863 return ret;
864 }
866 int socket(int domain, int type, int protocol)
867 {
868 int fd, res;
869 fd = lwip_socket(domain, type, protocol);
870 if (fd < 0)
871 return -1;
872 res = alloc_fd(FTYPE_SOCKET);
873 printk("socket -> %d\n", res);
874 files[res].socket.fd = fd;
875 return res;
876 }
878 int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
879 {
880 int fd, res;
881 if (files[s].type != FTYPE_SOCKET) {
882 printk("accept(%d): Bad descriptor\n", s);
883 errno = EBADF;
884 return -1;
885 }
886 fd = lwip_accept(files[s].socket.fd, addr, addrlen);
887 if (fd < 0)
888 return -1;
889 res = alloc_fd(FTYPE_SOCKET);
890 files[res].socket.fd = fd;
891 printk("accepted on %d -> %d\n", s, res);
892 return res;
893 }
895 #define LWIP_STUB(ret, name, proto, args) \
896 ret name proto \
897 { \
898 if (files[s].type != FTYPE_SOCKET) { \
899 printk(#name "(%d): Bad descriptor\n", s); \
900 errno = EBADF; \
901 return -1; \
902 } \
903 s = files[s].socket.fd; \
904 return lwip_##name args; \
905 }
907 LWIP_STUB(int, bind, (int s, struct sockaddr *my_addr, socklen_t addrlen), (s, my_addr, addrlen))
908 LWIP_STUB(int, getsockopt, (int s, int level, int optname, void *optval, socklen_t *optlen), (s, level, optname, optval, optlen))
909 LWIP_STUB(int, setsockopt, (int s, int level, int optname, void *optval, socklen_t optlen), (s, level, optname, optval, optlen))
910 LWIP_STUB(int, connect, (int s, struct sockaddr *serv_addr, socklen_t addrlen), (s, serv_addr, addrlen))
911 LWIP_STUB(int, listen, (int s, int backlog), (s, backlog));
912 LWIP_STUB(ssize_t, recv, (int s, void *buf, size_t len, int flags), (s, buf, len, flags))
913 LWIP_STUB(ssize_t, recvfrom, (int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen), (s, buf, len, flags, from, fromlen))
914 LWIP_STUB(ssize_t, send, (int s, void *buf, size_t len, int flags), (s, buf, len, flags))
915 LWIP_STUB(ssize_t, sendto, (int s, void *buf, size_t len, int flags, struct sockaddr *to, socklen_t tolen), (s, buf, len, flags, to, tolen))
916 LWIP_STUB(int, getsockname, (int s, struct sockaddr *name, socklen_t *namelen), (s, name, namelen))
918 int nanosleep(const struct timespec *req, struct timespec *rem)
919 {
920 s_time_t start = NOW();
921 s_time_t stop = start + SECONDS(req->tv_sec) + req->tv_nsec;
922 s_time_t stopped;
923 struct thread *thread = get_current();
925 thread->wakeup_time = stop;
926 clear_runnable(thread);
927 schedule();
928 stopped = NOW();
930 if (rem)
931 {
932 s_time_t remaining = stop - stopped;
933 if (remaining > 0)
934 {
935 rem->tv_nsec = remaining % 1000000000ULL;
936 rem->tv_sec = remaining / 1000000000ULL;
937 } else memset(rem, 0, sizeof(*rem));
938 }
940 return 0;
941 }
943 int usleep(useconds_t usec)
944 {
945 /* "usec shall be less than one million." */
946 struct timespec req;
947 req.tv_nsec = usec * 1000;
948 req.tv_sec = 0;
950 if (nanosleep(&req, NULL))
951 return -1;
953 return 0;
954 }
956 unsigned int sleep(unsigned int seconds)
957 {
958 struct timespec req, rem;
959 req.tv_sec = seconds;
960 req.tv_nsec = 0;
962 if (nanosleep(&req, &rem))
963 return -1;
965 if (rem.tv_nsec > 0)
966 rem.tv_sec++;
968 return rem.tv_sec;
969 }
971 int clock_gettime(clockid_t clk_id, struct timespec *tp)
972 {
973 switch (clk_id) {
974 case CLOCK_MONOTONIC:
975 {
976 struct timeval tv;
978 gettimeofday(&tv, NULL);
980 tp->tv_sec = tv.tv_sec;
981 tp->tv_nsec = tv.tv_usec * 1000;
983 break;
984 }
985 case CLOCK_REALTIME:
986 {
987 u64 nsec = monotonic_clock();
989 tp->tv_sec = nsec / 1000000000ULL;
990 tp->tv_nsec = nsec % 1000000000ULL;
992 break;
993 }
994 default:
995 print_unsupported("clock_gettime(%d)", clk_id);
996 errno = EINVAL;
997 return -1;
998 }
1000 return 0;
1003 void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
1005 ASSERT(!start);
1006 length = (length + PAGE_SIZE - 1) & PAGE_MASK;
1007 ASSERT(prot == (PROT_READ|PROT_WRITE));
1008 ASSERT(flags == (MAP_SHARED|MAP_ANON) || flags == (MAP_PRIVATE|MAP_ANON));
1009 ASSERT(fd == -1);
1010 ASSERT(offset == 0);
1012 return map_zero(length / PAGE_SIZE, 1);
1014 #if defined(__x86_64__) || defined(__ia64__)
1015 __typeof__(mmap) mmap64 __attribute__((__alias__("mmap")));
1016 #endif
1018 int munmap(void *start, size_t length)
1020 int i, n = length / PAGE_SIZE;
1021 multicall_entry_t call[n];
1022 unsigned char (*data)[PAGE_SIZE] = start;
1023 int ret;
1024 ASSERT(!((unsigned long)start & ~PAGE_MASK));
1025 ASSERT(!(length & ~PAGE_MASK));
1027 for (i = 0; i < n; i++) {
1028 call[i].op = __HYPERVISOR_update_va_mapping;
1029 call[i].args[0] = (unsigned long) &data[i];
1030 call[i].args[1] = 0;
1031 call[i].args[2] = 0;
1032 call[i].args[3] = UVMF_INVLPG | UVMF_ALL;
1035 ret = HYPERVISOR_multicall(call, n);
1036 if (ret) {
1037 errno = -ret;
1038 return -1;
1041 for (i = 0; i < n; i++) {
1042 if (call[i].result) {
1043 errno = call[i].result;
1044 return -1;
1047 return 0;
1050 /* Not supported by FS yet. */
1051 unsupported_function_crash(link);
1052 unsupported_function(int, readlink, -1);
1054 /* We could support that. */
1055 unsupported_function_log(int, chdir, -1);
1057 /* No dynamic library support. */
1058 unsupported_function_log(void *, dlopen, NULL);
1059 unsupported_function_log(void *, dlsym, NULL);
1060 unsupported_function_log(char *, dlerror, NULL);
1061 unsupported_function_log(int, dlclose, -1);
1063 /* We don't raise signals anyway. */
1064 unsupported_function(int, sigemptyset, -1);
1065 unsupported_function(int, sigfillset, -1);
1066 unsupported_function(int, sigaddset, -1);
1067 unsupported_function(int, sigdelset, -1);
1068 unsupported_function(int, sigismember, -1);
1069 unsupported_function(int, sigprocmask, -1);
1070 unsupported_function(int, sigaction, -1);
1071 unsupported_function(int, __sigsetjmp, 0);
1072 unsupported_function(int, sigaltstack, -1);
1073 unsupported_function_crash(kill);
1075 /* Linuxish abi for the Caml runtime, don't support */
1076 unsupported_function_log(struct dirent *, readdir64, NULL);
1077 unsupported_function_log(int, getrusage, -1);
1078 unsupported_function_log(int, getrlimit, -1);
1079 unsupported_function_log(int, getrlimit64, -1);
1080 unsupported_function_log(int, __xstat64, -1);
1081 unsupported_function_log(long, __strtol_internal, LONG_MIN);
1082 unsupported_function_log(double, __strtod_internal, HUGE_VAL);
1083 #endif