Use weak __thread declarations in parlib-compat (XCC)
[akaros.git] / tools / compilers / gcc-glibc / glibc-2.19-akaros / sysdeps / akaros / user_fd.c
1 /* Copyright (c) 2015 Google Inc.
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * User FDs
6  *
7  * There are a bunch of Linux APIs that we can implement in userspace that use
8  * FDs as a handle.  Eventually that handle gets passed to close().  User FDs
9  * are a chunk of reserved numbers in the space of FDs, used by various
10  * userspace libraries that use FDs as their API.
11  *
12  * The user FD space starts where the kernel's leaves off.  Currently, the
13  * kernel claims 19 bits of the 32 bit int for an FD.  The MSB flags whether it
14  * is negative or not.  That leaves 12 bits for us. */
15
16 #include <sys/user_fd.h>
17 #include <parlib/arch/atomic.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21
22 static struct user_fd **ufds = 0;
23 static size_t nr_ufds = 0;
24
25 /* Finds a free user FD and stores ufd there.  Returns the FD, or -1 on error
26  * (out of FDs).  You can remove it with a close(). */
27 int ufd_get_fd(struct user_fd *ufd)
28 {
29         struct user_fd **new_ufds;
30         int fd;
31
32         if (!ufds) {
33                 nr_ufds = 1 << (sizeof(int) * 8 - LOG2_UP(NR_FILE_DESC_MAX) - 1);
34                 /* Two things: instead of worrying about growing and reallocing (which
35                  * would need a lock), let's just alloc the entire 2^15 bytes (32KB).
36                  * Also, it's unlikely, but we might have two threads trying to init at
37                  * once.  First one wins, second one aborts (and frees). */
38                 new_ufds = malloc(sizeof(struct user_fd*) * nr_ufds);
39                 memset(new_ufds, 0, sizeof(struct user_fd*) * nr_ufds);
40                 if (!atomic_cas_ptr((void**)&ufds, 0, new_ufds))
41                         free(new_ufds);
42                 cmb();
43         }
44         /* At this point, ufds is set.  Just do a linear search for an empty slot.
45          * We're not actually bound to return the lowest number available, so in the
46          * future we could do things like partition the space based on vcoreid so we
47          * start in different areas, or maintain a 'last used' hint FD. */
48         for (int i = 0; i < nr_ufds; i++) {
49                 if (!ufds[i]) {
50                         if (atomic_cas_ptr((void**)&ufds[i], 0, ufd)) {
51                                 fd = i + USER_FD_BASE;
52                                 ufds[i]->fd = fd;
53                                 return fd;
54                         }
55                 }
56         }
57         __set_errno(ENFILE);
58         return -1;
59 }
60
61 /* Given an FD, returns the user_fd struct.  Returns 0 and sets errno if there's
62  * an error.  There's no protection for concurrent closes, just like how you
63  * shouldn't attempt to use an FD after closing.  So don't do stuff like:
64  *              foo = ufd_lookup(7);
65  *                                                         close(7);
66  *              foo->whatever = 6; // foo could be free!
67  *
68  * or
69  *                                                         close(7);
70  *              foo = ufd_lookup(7);
71  *      // this might succeed if it races with close()
72  *              foo->whatever = 6; // foo could be free!
73  */
74 struct user_fd *ufd_lookup(int fd)
75 {
76         if (!ufds || (fd - USER_FD_BASE >= nr_ufds)) {
77                 __set_errno(EBADF);
78                 return 0;
79         }
80         return ufds[fd - USER_FD_BASE];
81 }
82
83 /* Removes the user_fd from the FD space, calls its callback.  Returns 0 on
84  * success.  -1 and sets errno o/w (e.g. EBADF). */
85 int glibc_close_helper(int fd)
86 {
87         struct user_fd *ufd = ufd_lookup(fd);
88         if (!ufd)
89                 return -1;
90         ufds[fd - USER_FD_BASE] = 0;
91         ufd->close(ufd);
92         return 0;
93 }