db_eventfd.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /* Copyright (C) 2019 Intel Corporation
  2. This file is part of Graphene Library OS.
  3. Graphene Library OS is free software: you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public License
  5. as published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. Graphene Library OS is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. /*
  14. * db_eventfd.c
  15. *
  16. * This file contains operations to handle streams with URIs that have "eventfd:".
  17. */
  18. #include <asm/fcntl.h>
  19. #include <asm/poll.h>
  20. #include <linux/time.h>
  21. #include <linux/types.h>
  22. #include <linux/un.h>
  23. #include <sys/eventfd.h>
  24. #include "api.h"
  25. #include "pal.h"
  26. #include "pal_debug.h"
  27. #include "pal_defs.h"
  28. #include "pal_error.h"
  29. #include "pal_internal.h"
  30. #include "pal_linux.h"
  31. #include "pal_linux_defs.h"
  32. #include "pal_linux_error.h"
  33. #include "pal_security.h"
  34. static inline int eventfd_type(int options) {
  35. int type = 0;
  36. if (options & PAL_OPTION_NONBLOCK)
  37. type |= EFD_NONBLOCK;
  38. if (options & PAL_OPTION_CLOEXEC)
  39. type |= EFD_CLOEXEC;
  40. if (options & PAL_OPTION_EFD_SEMAPHORE)
  41. type |= EFD_SEMAPHORE;
  42. return type;
  43. }
  44. /* `type` must be eventfd, `uri` & `access` & `share` are unused, `create` holds eventfd's initval,
  45. * `options` holds eventfd's flags */
  46. static int eventfd_pal_open(PAL_HANDLE* handle, const char* type, const char* uri, int access,
  47. int share, int create, int options) {
  48. int ret;
  49. __UNUSED(access);
  50. __UNUSED(share);
  51. if ((strcmp_static(type, URI_TYPE_EVENTFD) != 0) || (*uri != '\0')) {
  52. return -PAL_ERROR_INVAL;
  53. }
  54. /* Using create arg as a work-around (note: initval is uint32 but create is int32).*/
  55. ret = INLINE_SYSCALL(eventfd2, 2, create, eventfd_type(options));
  56. if (IS_ERR(ret))
  57. return unix_to_pal_error(ERRNO(ret));
  58. PAL_HANDLE hdl = malloc(HANDLE_SIZE(eventfd));
  59. SET_HANDLE_TYPE(hdl, eventfd);
  60. /* Note: using index 0, given that there is only 1 eventfd FD per pal-handle. */
  61. HANDLE_HDR(hdl)->flags = RFD(0) | WFD(0) | WRITABLE(0);
  62. hdl->eventfd.fd = ret;
  63. hdl->eventfd.nonblocking = (options & PAL_OPTION_NONBLOCK) ? PAL_TRUE : PAL_FALSE;
  64. *handle = hdl;
  65. return 0;
  66. }
  67. static int64_t eventfd_pal_read(PAL_HANDLE handle, uint64_t offset, uint64_t len, void* buffer) {
  68. if (offset)
  69. return -PAL_ERROR_INVAL;
  70. if (!IS_HANDLE_TYPE(handle, eventfd))
  71. return -PAL_ERROR_NOTCONNECTION;
  72. if (len < sizeof(uint64_t))
  73. return -PAL_ERROR_INVAL;
  74. int bytes = INLINE_SYSCALL(read, 3, handle->eventfd.fd, buffer, len);
  75. if (IS_ERR(bytes))
  76. return unix_to_pal_error(ERRNO(bytes));
  77. if (!bytes)
  78. return -PAL_ERROR_ENDOFSTREAM;
  79. return bytes;
  80. }
  81. static int64_t eventfd_pal_write(PAL_HANDLE handle, uint64_t offset, uint64_t len,
  82. const void* buffer) {
  83. if (offset)
  84. return -PAL_ERROR_INVAL;
  85. if (!IS_HANDLE_TYPE(handle, eventfd))
  86. return -PAL_ERROR_NOTCONNECTION;
  87. if (len < sizeof(uint64_t))
  88. return -PAL_ERROR_INVAL;
  89. int bytes = INLINE_SYSCALL(write, 3, handle->eventfd.fd, buffer, len);
  90. PAL_FLG writable = WRITABLE(0);
  91. if (IS_ERR(bytes)) {
  92. if (ERRNO(bytes) == EAGAIN)
  93. HANDLE_HDR(handle)->flags &= ~writable;
  94. return unix_to_pal_error(ERRNO(bytes));
  95. }
  96. /* whether fd is writable or not, gets updated here, to optimize polling logic in
  97. * _DkObjectsWaitAny */
  98. if ((uint64_t)bytes == sizeof(uint64_t))
  99. HANDLE_HDR(handle)->flags |= writable;
  100. else
  101. HANDLE_HDR(handle)->flags &= ~writable;
  102. return bytes;
  103. }
  104. /* invoked during poll operation on eventfd from LibOS. */
  105. static int eventfd_pal_attrquerybyhdl(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) {
  106. if (handle->generic.fds[0] == PAL_IDX_POISON)
  107. return -PAL_ERROR_BADHANDLE;
  108. attr->handle_type = PAL_GET_TYPE(handle);
  109. int efd = handle->eventfd.fd;
  110. int flags = HANDLE_HDR(handle)->flags;
  111. struct pollfd pfd = {.fd = efd, .events = POLLIN, .revents = 0};
  112. struct timespec tp = {0, 0};
  113. int ret = INLINE_SYSCALL(ppoll, 5, &pfd, 1, &tp, NULL, 0);
  114. if (IS_ERR(ret))
  115. return unix_to_pal_error(ERRNO(ret));
  116. attr->readable = (ret == 1 && pfd.revents == POLLIN);
  117. attr->disconnected = flags & ERROR(0);
  118. attr->nonblocking = handle->eventfd.nonblocking;
  119. /* For future use, so that Linux host kernel can send notifications to user-space apps. App
  120. * receives virtual FD from LibOS, but the Linux-host eventfd is memorized here, such that this
  121. * Linux-host eventfd can be retrieved (by LibOS) during app's ioctl(). */
  122. attr->no_of_fds = 1;
  123. attr->fds[0] = efd;
  124. return 0;
  125. }
  126. static int eventfd_pal_close(PAL_HANDLE handle) {
  127. if (IS_HANDLE_TYPE(handle, eventfd)) {
  128. if (handle->eventfd.fd != PAL_IDX_POISON) {
  129. INLINE_SYSCALL(close, 1, handle->eventfd.fd);
  130. handle->eventfd.fd = PAL_IDX_POISON;
  131. }
  132. }
  133. return 0;
  134. }
  135. struct handle_ops eventfd_ops = {
  136. .open = &eventfd_pal_open,
  137. .read = &eventfd_pal_read,
  138. .write = &eventfd_pal_write,
  139. .close = &eventfd_pal_close,
  140. .attrquerybyhdl = &eventfd_pal_attrquerybyhdl,
  141. };