libsync.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /*
  2. * sync abstraction
  3. * Copyright 2015-2016 Collabora Ltd.
  4. *
  5. * Based on the implementation from the Android Open Source Project,
  6. *
  7. * Copyright 2012 Google, Inc
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a
  10. * copy of this software and associated documentation files (the "Software"),
  11. * to deal in the Software without restriction, including without limitation
  12. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  13. * and/or sell copies of the Software, and to permit persons to whom the
  14. * Software is furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  22. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  23. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  24. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  25. * OTHER DEALINGS IN THE SOFTWARE.
  26. */
  27. #ifndef _LIBSYNC_H
  28. #define _LIBSYNC_H
  29. #include <assert.h>
  30. #include <errno.h>
  31. #include <stdint.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <sys/ioctl.h>
  35. #include <sys/poll.h>
  36. #include <unistd.h>
  37. #if defined(__cplusplus)
  38. extern "C" {
  39. #endif
  40. #ifndef SYNC_IOC_MAGIC
  41. #define SYNC_IOC_MAGIC '>'
  42. #endif
  43. #ifndef SYNC_IOC_MERGE
  44. /* duplicated from linux/sync_file.h to avoid build-time dependency
  45. * on new (v4.7) kernel headers. Once distro's are mostly using
  46. * something newer than v4.7 drop this and #include <linux/sync_file.h>
  47. * instead.
  48. */
  49. struct sync_merge_data {
  50. char name[32];
  51. int32_t fd2;
  52. int32_t fence;
  53. uint32_t flags;
  54. uint32_t pad;
  55. };
  56. #define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
  57. #endif
  58. #ifndef SYNC_IOC_LEGACY_MERGE
  59. /* the legacy definitions are based on the contents of
  60. * drivers/staging/android/uapi/sync.h in the v4.4 kernel.
  61. */
  62. struct sync_legacy_merge_data {
  63. int32_t fd2;
  64. char name[32];
  65. int32_t fence;
  66. };
  67. #define SYNC_IOC_LEGACY_MERGE _IOWR(SYNC_IOC_MAGIC, 1, \
  68. struct sync_legacy_merge_data)
  69. #endif
  70. #ifndef SYNC_IOC_FILE_INFO
  71. /* duplicated from linux/sync_file.h to avoid a build-time dependency
  72. * on new (v4.7) kernel headers.
  73. */
  74. struct sync_fence_info {
  75. char obj_name[32];
  76. char driver_name[32];
  77. int32_t status;
  78. uint32_t flags;
  79. uint64_t timestamp_ns;
  80. };
  81. struct sync_file_info {
  82. char name[32];
  83. int32_t status;
  84. uint32_t flags;
  85. uint32_t num_fences;
  86. uint32_t pad;
  87. uint64_t sync_fence_info;
  88. };
  89. #define SYNC_IOC_FILE_INFO _IOWR(SYNC_IOC_MAGIC, 4, struct sync_file_info)
  90. #endif
  91. #ifndef SYNC_IOC_LEGACY_FENCE_INFO
  92. /* the legacy definitions are based on the contents of
  93. * drivers/staging/android/uapi/sync.h in the v4.4 kernel.
  94. */
  95. struct sync_pt_info {
  96. uint32_t len;
  97. char obj_name[32];
  98. char driver_name[32];
  99. int32_t status;
  100. uint64_t timestamp_ns;
  101. uint8_t driver_data[0];
  102. };
  103. struct sync_fence_info_data {
  104. uint32_t len;
  105. char name[32];
  106. int32_t status;
  107. uint8_t pt_info[0];
  108. };
  109. #define SYNC_IOC_LEGACY_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2, \
  110. struct sync_fence_info_data)
  111. #endif
  112. static inline int sync_wait(int fd, int timeout)
  113. {
  114. struct pollfd fds = {0};
  115. int ret;
  116. fds.fd = fd;
  117. fds.events = POLLIN;
  118. do {
  119. ret = poll(&fds, 1, timeout);
  120. if (ret > 0) {
  121. if (fds.revents & (POLLERR | POLLNVAL)) {
  122. errno = EINVAL;
  123. return -1;
  124. }
  125. return 0;
  126. } else if (ret == 0) {
  127. errno = ETIME;
  128. return -1;
  129. }
  130. } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
  131. return ret;
  132. }
  133. static inline int sync_legacy_merge(const char *name, int fd1, int fd2)
  134. {
  135. struct sync_legacy_merge_data data;
  136. int ret;
  137. data.fd2 = fd2;
  138. strncpy(data.name, name, sizeof(data.name));
  139. do {
  140. ret = ioctl(fd1, SYNC_IOC_LEGACY_MERGE, &data);
  141. } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
  142. if (ret < 0)
  143. return ret;
  144. return data.fence;
  145. }
  146. static inline int sync_merge(const char *name, int fd1, int fd2)
  147. {
  148. struct sync_merge_data data = {0};
  149. int ret;
  150. data.fd2 = fd2;
  151. strncpy(data.name, name, sizeof(data.name));
  152. do {
  153. ret = ioctl(fd1, SYNC_IOC_MERGE, &data);
  154. } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
  155. if (ret < 0) {
  156. if (errno == ENOTTY)
  157. return sync_legacy_merge(name, fd1, fd2);
  158. else
  159. return ret;
  160. }
  161. return data.fence;
  162. }
  163. /* accumulate fd2 into fd1. If *fd1 is not a valid fd then dup fd2,
  164. * otherwise sync_merge() and close the old *fd1. This can be used
  165. * to implement the pattern:
  166. *
  167. * init()
  168. * {
  169. * batch.fence_fd = -1;
  170. * }
  171. *
  172. * // does *NOT* take ownership of fd
  173. * server_sync(int fd)
  174. * {
  175. * if (sync_accumulate("foo", &batch.fence_fd, fd)) {
  176. * ... error ...
  177. * }
  178. * }
  179. */
  180. static inline int sync_accumulate(const char *name, int *fd1, int fd2)
  181. {
  182. int ret;
  183. assert(fd2 >= 0);
  184. if (*fd1 < 0) {
  185. *fd1 = dup(fd2);
  186. return 0;
  187. }
  188. ret = sync_merge(name, *fd1, fd2);
  189. if (ret < 0) {
  190. /* leave *fd1 as it is */
  191. return ret;
  192. }
  193. close(*fd1);
  194. *fd1 = ret;
  195. return 0;
  196. }
  197. static inline struct sync_pt_info *sync_pt_info(
  198. struct sync_fence_info_data *info,
  199. struct sync_pt_info *pt_info)
  200. {
  201. if (!pt_info)
  202. pt_info = (struct sync_pt_info *)info->pt_info;
  203. else
  204. pt_info = (struct sync_pt_info *)((uint8_t *)pt_info +
  205. pt_info->len);
  206. if ((uint32_t)((uint8_t *)pt_info - (uint8_t *)info) >= info->len)
  207. return NULL;
  208. return pt_info;
  209. }
  210. static inline struct sync_fence_info_data *sync_legacy_fence_info(int fd)
  211. {
  212. const uint32_t len = 4096;
  213. struct sync_fence_info_data *info = malloc(len);
  214. int ret;
  215. if (!info)
  216. return NULL;
  217. info->len = len;
  218. do {
  219. ret = ioctl(fd, SYNC_IOC_LEGACY_FENCE_INFO, info);
  220. } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
  221. if (ret < 0) {
  222. free(info);
  223. return NULL;
  224. }
  225. return info;
  226. }
  227. static inline struct sync_fence_info_data *fence_info_from_file_info(
  228. struct sync_file_info *file_info,
  229. uint32_t num_fences)
  230. {
  231. struct sync_fence_info_data *info;
  232. size_t info_len;
  233. struct sync_pt_info *pt_info = NULL;
  234. struct sync_fence_info *fence_info;
  235. uint32_t i;
  236. info_len = sizeof(*info) + num_fences * sizeof(*pt_info);
  237. info = malloc(info_len);
  238. if (!info)
  239. return NULL;
  240. info->len = info_len;
  241. strncpy(info->name, file_info->name, sizeof(info->name));
  242. info->status = file_info->status;
  243. fence_info = (struct sync_fence_info *)(uintptr_t)
  244. file_info->sync_fence_info;
  245. for (i = 0; i < num_fences; i++) {
  246. pt_info = sync_pt_info(info, pt_info);
  247. assert(pt_info);
  248. pt_info->len = sizeof(*pt_info);
  249. strncpy(pt_info->obj_name, fence_info->obj_name,
  250. sizeof(pt_info->obj_name));
  251. strncpy(pt_info->driver_name, fence_info->driver_name,
  252. sizeof(pt_info->driver_name));
  253. pt_info->status = fence_info->status;
  254. pt_info->timestamp_ns = fence_info->timestamp_ns;
  255. fence_info++;
  256. }
  257. return info;
  258. }
  259. static inline struct sync_fence_info_data *sync_fence_info(int fd)
  260. {
  261. struct sync_fence_info_data *info = NULL;
  262. struct sync_file_info initial_info = {""};
  263. struct sync_file_info *file_info;
  264. int ret;
  265. do {
  266. ret = ioctl(fd, SYNC_IOC_FILE_INFO, &initial_info);
  267. } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
  268. if (ret < 0) {
  269. if (errno == ENOTTY)
  270. return sync_legacy_fence_info(fd);
  271. else
  272. return NULL;
  273. }
  274. file_info = calloc(1, sizeof(*file_info) + initial_info.num_fences *
  275. sizeof(struct sync_fence_info));
  276. if (!file_info)
  277. return NULL;
  278. file_info->num_fences = initial_info.num_fences;
  279. file_info->sync_fence_info = (uint64_t)(uintptr_t)(file_info + 1);
  280. do {
  281. ret = ioctl(fd, SYNC_IOC_FILE_INFO, file_info);
  282. } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
  283. if (ret < 0)
  284. goto free_file_info;
  285. info = fence_info_from_file_info(file_info, initial_info.num_fences);
  286. free_file_info:
  287. free(file_info);
  288. return info;
  289. }
  290. static inline void sync_fence_info_free(struct sync_fence_info_data *info)
  291. {
  292. free(info);
  293. }
  294. static inline struct sync_fence_info *sync_get_fence_info(
  295. struct sync_file_info *file_info)
  296. {
  297. return (struct sync_fence_info *)(uintptr_t)file_info->sync_fence_info;
  298. }
  299. static inline struct sync_file_info *file_info_from_info_data(
  300. struct sync_fence_info_data *info)
  301. {
  302. struct sync_pt_info *pt_info = NULL;
  303. uint32_t num_fences = 0;
  304. struct sync_file_info *file_info;
  305. struct sync_fence_info *fence_info;
  306. uint32_t i;
  307. while ((pt_info = sync_pt_info(info, pt_info)) != NULL)
  308. num_fences++;
  309. file_info = calloc(1, sizeof(*file_info) + num_fences *
  310. sizeof(*fence_info));
  311. if (!file_info)
  312. return NULL;
  313. strncpy(file_info->name, info->name, sizeof(file_info->name));
  314. file_info->status = info->status;
  315. file_info->num_fences = num_fences;
  316. file_info->sync_fence_info = (uint64_t)(uintptr_t)(file_info + 1);
  317. fence_info = sync_get_fence_info(file_info);
  318. for (i = 0; i < num_fences; i++) {
  319. pt_info = sync_pt_info(info, pt_info);
  320. assert(pt_info);
  321. strncpy(fence_info->obj_name, pt_info->obj_name,
  322. sizeof(fence_info->obj_name));
  323. strncpy(fence_info->driver_name, pt_info->driver_name,
  324. sizeof(fence_info->driver_name));
  325. fence_info->status = pt_info->status;
  326. fence_info->timestamp_ns = pt_info->timestamp_ns;
  327. fence_info++;
  328. }
  329. return file_info;
  330. }
  331. static inline struct sync_file_info *sync_legacy_file_info(int fd)
  332. {
  333. const uint32_t len = 4096;
  334. struct sync_fence_info_data *info = malloc(len);
  335. struct sync_file_info *file_info;
  336. int ret;
  337. if (!info)
  338. return NULL;
  339. info->len = len;
  340. do {
  341. ret = ioctl(fd, SYNC_IOC_LEGACY_FENCE_INFO, info);
  342. } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
  343. if (ret < 0) {
  344. free(info);
  345. return NULL;
  346. }
  347. file_info = file_info_from_info_data(info);
  348. free(info);
  349. return file_info;
  350. }
  351. static inline void sync_file_info_free(struct sync_file_info *file_info)
  352. {
  353. free(file_info);
  354. }
  355. static inline struct sync_file_info *sync_file_info(int fd)
  356. {
  357. struct sync_file_info initial_info = {""};
  358. struct sync_file_info *file_info;
  359. int ret;
  360. do {
  361. ret = ioctl(fd, SYNC_IOC_FILE_INFO, &initial_info);
  362. } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
  363. if (ret < 0) {
  364. if (errno == ENOTTY)
  365. return sync_legacy_file_info(fd);
  366. else
  367. return NULL;
  368. }
  369. file_info = calloc(1, sizeof(*file_info) + initial_info.num_fences *
  370. sizeof(struct sync_fence_info));
  371. if (!file_info)
  372. return NULL;
  373. file_info->num_fences = initial_info.num_fences;
  374. file_info->sync_fence_info = (uint64_t)(uintptr_t)(file_info + 1);
  375. do {
  376. ret = ioctl(fd, SYNC_IOC_FILE_INFO, file_info);
  377. } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
  378. if (ret < 0) {
  379. sync_file_info_free(file_info);
  380. return NULL;
  381. }
  382. return file_info;
  383. }
  384. #if defined(__cplusplus)
  385. }
  386. #endif
  387. #endif