aispoll.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /*
  2. * Copyright (c) 2003-2004 MontaVista Software, Inc.
  3. *
  4. * All rights reserved.
  5. *
  6. * Author: Steven Dake (sdake@mvista.com)
  7. *
  8. * This software licensed under BSD license, the text of which follows:
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * - Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. * - Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. * - Neither the name of the MontaVista Software, Inc. nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  32. * THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include <errno.h>
  35. #include <pthread.h>
  36. #include <sys/poll.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include "aispoll.h"
  40. #include "../include/list.h"
  41. #include "tlist.h"
  42. typedef int (*dispatch_fn_t) (poll_handle poll_handle, int fd, int revents, void *data);
  43. struct poll_instance {
  44. struct pollfd *ufds;
  45. int nfds;
  46. dispatch_fn_t *dispatch_fns;
  47. void **data;
  48. struct timerlist timerlist;
  49. pthread_mutex_t mutex;
  50. };
  51. #define POLLINSTANCE_MUTEX_OFFSET offset_of(struct poll_instance, mutex)
  52. struct handle {
  53. int valid;
  54. void *instance;
  55. unsigned int generation;
  56. };
  57. struct handle_database {
  58. unsigned int handle_count;
  59. struct handle *handles;
  60. unsigned int generation;
  61. pthread_mutex_t mutex;
  62. };
  63. #define offset_of(type,member) (int)(&(((type *)0)->member))
  64. #define HANDLECONVERT_NOLOCKING 0x80000000
  65. #define HANDLECONVERT_DONTUNLOCKDB 0x40000000
  66. int handle_create (
  67. struct handle_database *handle_database,
  68. void **instance_out,
  69. int instance_size,
  70. int *handle_out)
  71. {
  72. int handle;
  73. void *new_handles;
  74. int found = 0;
  75. void *instance;
  76. pthread_mutex_lock (&handle_database->mutex);
  77. for (handle = 0; handle < handle_database->handle_count; handle++) {
  78. if (handle_database->handles[handle].valid == 0) {
  79. found = 1;
  80. break;
  81. }
  82. }
  83. if (found == 0) {
  84. handle_database->handle_count += 1;
  85. new_handles = (struct handle *)realloc (handle_database->handles,
  86. sizeof (struct handle) * handle_database->handle_count);
  87. if (new_handles == 0) {
  88. pthread_mutex_unlock (&handle_database->mutex);
  89. errno = ENOMEM;
  90. return (-1);
  91. }
  92. handle_database->handles = new_handles;
  93. }
  94. instance = (void *)malloc (instance_size);
  95. if (instance == 0) {
  96. errno = ENOMEM;
  97. return (-1);
  98. }
  99. memset (instance, 0, instance_size);
  100. handle_database->handles[handle].valid = 1;
  101. handle_database->handles[handle].instance = instance;
  102. handle_database->handles[handle].generation = handle_database->generation++;
  103. *handle_out = handle;
  104. *instance_out = instance;
  105. pthread_mutex_unlock (&handle_database->mutex);
  106. return (0);
  107. }
  108. int handle_convert (
  109. struct handle_database *handle_database,
  110. unsigned int handle,
  111. void **instance,
  112. int offset_to_mutex,
  113. unsigned int *generation_out)
  114. {
  115. int unlock_db;
  116. int locking;
  117. unlock_db = (0 == (offset_to_mutex & HANDLECONVERT_DONTUNLOCKDB));
  118. locking = (0 == (offset_to_mutex & HANDLECONVERT_NOLOCKING));
  119. offset_to_mutex &= 0x00fffff; /* remove 8 bits of flags */
  120. if (locking) {
  121. pthread_mutex_lock (&handle_database->mutex);
  122. }
  123. /* Add this later
  124. res = saHandleVerify (handle_database, handle);
  125. if (res == -1) {
  126. if (locking) {
  127. pthread_mutex_unlock (&handle_database->mutex);
  128. }
  129. errno = ENOENT;
  130. return (-1);
  131. }
  132. */
  133. *instance = handle_database->handles[handle].instance;
  134. if (generation_out) {
  135. *generation_out = handle_database->handles[handle].generation;
  136. }
  137. /*
  138. * This function exits holding the mutex in the instance instance
  139. * pointed to by offset_to_mutex (if NOLOCKING isn't set)
  140. */
  141. if (locking) {
  142. pthread_mutex_lock ((pthread_mutex_t *)(*instance + offset_to_mutex));
  143. if (unlock_db) {
  144. pthread_mutex_unlock (&handle_database->mutex);
  145. }
  146. }
  147. return (0);
  148. }
  149. /*
  150. * All instances in one database
  151. */
  152. static struct handle_database poll_instance_database = {
  153. handle_count: 0,
  154. handles: 0,
  155. generation: 0,
  156. mutex: PTHREAD_MUTEX_INITIALIZER
  157. };
  158. poll_handle poll_create (void)
  159. {
  160. poll_handle poll_handle;
  161. struct poll_instance *poll_instance;
  162. int res;
  163. res = handle_create (&poll_instance_database, (void *)&poll_instance,
  164. sizeof (struct poll_instance), &poll_handle);
  165. if (res == -1) {
  166. goto error_exit;
  167. }
  168. poll_instance->ufds = 0;
  169. poll_instance->nfds = 0;
  170. poll_instance->dispatch_fns = 0;
  171. poll_instance->data = 0;
  172. timerlist_init (&poll_instance->timerlist);
  173. return (poll_handle);
  174. error_exit:
  175. return (-1);
  176. }
  177. int poll_destroy (poll_handle poll_handle)
  178. {
  179. struct poll_instance *poll_instance;
  180. int res;
  181. res = handle_convert (&poll_instance_database, poll_handle,
  182. (void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
  183. if (res == -1) {
  184. goto error_exit;
  185. }
  186. if (poll_instance->ufds) {
  187. free (poll_instance->ufds);
  188. }
  189. if (poll_instance->dispatch_fns) {
  190. free (poll_instance->dispatch_fns);
  191. }
  192. if (poll_instance->data) {
  193. free (poll_instance->data);
  194. }
  195. timerlist_free (&poll_instance->timerlist);
  196. // TODO destroy poll
  197. return (0);
  198. error_exit:
  199. return (-1);
  200. }
  201. int poll_dispatch_add (
  202. poll_handle handle,
  203. int fd,
  204. int events,
  205. void *data,
  206. int (*dispatch_fn) (poll_handle poll_handle, int fd, int revents, void *data))
  207. {
  208. struct poll_instance *poll_instance;
  209. struct pollfd *ufds;
  210. dispatch_fn_t *dispatch_fns;
  211. void **data_list;
  212. int res;
  213. int found = 0;
  214. int install_pos;
  215. res = handle_convert (&poll_instance_database, handle,
  216. (void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
  217. if (res == -1) {
  218. goto error_exit;
  219. }
  220. for (found = 0, install_pos = 0; install_pos < poll_instance->nfds; install_pos++) {
  221. if (poll_instance->ufds[install_pos].fd == -1) {
  222. found = 1;
  223. break;
  224. }
  225. }
  226. if (found == 0) {
  227. /*
  228. * Grow pollfd list
  229. */
  230. ufds = (struct pollfd *)realloc (poll_instance->ufds,
  231. (poll_instance->nfds + 1) * sizeof (struct pollfd));
  232. if (ufds == 0) {
  233. errno = ENOMEM;
  234. goto error_exit;
  235. }
  236. poll_instance->ufds = ufds;
  237. /*
  238. * Grow dispatch functions list
  239. */
  240. dispatch_fns = (dispatch_fn_t *)realloc (poll_instance->dispatch_fns,
  241. (poll_instance->nfds + 1) * sizeof (dispatch_fn_t));
  242. if (dispatch_fns == 0) {
  243. errno = ENOMEM;
  244. goto error_exit;
  245. }
  246. poll_instance->dispatch_fns = dispatch_fns;
  247. /*
  248. * Grow data list
  249. */
  250. data_list = (void **)realloc (poll_instance->data,
  251. (poll_instance->nfds + 1) * sizeof (void *));
  252. if (data_list == 0) {
  253. errno = ENOMEM;
  254. goto error_exit;
  255. }
  256. poll_instance->data = data_list;
  257. poll_instance->nfds += 1;
  258. install_pos = poll_instance->nfds - 1;
  259. }
  260. /*
  261. * Install new dispatch handler
  262. */
  263. poll_instance->ufds[install_pos].fd = fd;
  264. poll_instance->ufds[install_pos].events = events;
  265. poll_instance->ufds[install_pos].revents = 0;
  266. poll_instance->dispatch_fns[install_pos] = dispatch_fn;
  267. poll_instance->data[install_pos] = data;
  268. return (0);
  269. error_exit:
  270. return (-1);
  271. }
  272. int poll_dispatch_modify (
  273. poll_handle handle,
  274. int fd,
  275. int events,
  276. int (*dispatch_fn) (poll_handle poll_handle, int fd, int revents, void *data))
  277. {
  278. struct poll_instance *poll_instance;
  279. int i;
  280. int res;
  281. res = handle_convert (&poll_instance_database, handle,
  282. (void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
  283. if (res == -1) {
  284. return (-1);
  285. }
  286. /*
  287. * Find file descriptor to modify events and dispatch function
  288. */
  289. for (i = 0; i < poll_instance->nfds; i++) {
  290. if (poll_instance->ufds[i].fd == fd) {
  291. poll_instance->ufds[i].events = events;
  292. poll_instance->dispatch_fns[i] = dispatch_fn;
  293. return (0);
  294. }
  295. }
  296. errno = EBADF;
  297. return (-1);
  298. }
  299. int poll_dispatch_delete (
  300. poll_handle handle,
  301. int fd)
  302. {
  303. struct poll_instance *poll_instance;
  304. int i;
  305. int res;
  306. int found = 0;
  307. res = handle_convert (&poll_instance_database, handle,
  308. (void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
  309. if (res == -1) {
  310. goto error_exit;
  311. }
  312. /*
  313. * Find dispatch fd to delete
  314. */
  315. for (i = 0; i < poll_instance->nfds; i++) {
  316. if (poll_instance->ufds[i].fd == fd) {
  317. found = 1;
  318. break;
  319. }
  320. }
  321. if (found) {
  322. poll_instance->ufds[i].fd = -1;
  323. return (0);
  324. }
  325. error_exit:
  326. errno = EBADF;
  327. return (-1);
  328. }
  329. int poll_timer_add (
  330. poll_handle handle,
  331. int msec_in_future, void *data,
  332. void (*timer_fn) (void *data),
  333. poll_timer_handle *timer_handle_out)
  334. {
  335. struct poll_instance *poll_instance;
  336. poll_timer_handle timer_handle;
  337. int res;
  338. res = handle_convert (&poll_instance_database, handle,
  339. (void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
  340. if (res == -1) {
  341. return (-1);
  342. }
  343. timer_handle = (poll_timer_handle)timerlist_add_future (&poll_instance->timerlist,
  344. timer_fn, data, msec_in_future);
  345. if (timer_handle != 0) {
  346. *timer_handle_out = timer_handle;
  347. return (0);
  348. }
  349. return (-1);
  350. }
  351. int poll_timer_delete (
  352. poll_handle handle,
  353. poll_timer_handle timer_handle)
  354. {
  355. struct poll_instance *poll_instance;
  356. int res;
  357. if (timer_handle == 0) {
  358. return (0);
  359. }
  360. res = handle_convert (&poll_instance_database, handle,
  361. (void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
  362. if (res == -1) {
  363. return (-1);
  364. }
  365. timerlist_del (&poll_instance->timerlist, (void *)timer_handle);
  366. return (0);
  367. }
  368. int poll_run (
  369. poll_handle handle)
  370. {
  371. struct poll_instance *poll_instance;
  372. int i;
  373. int timeout = -1;
  374. int res;
  375. res = handle_convert (&poll_instance_database, handle,
  376. (void *)&poll_instance, POLLINSTANCE_MUTEX_OFFSET, 0);
  377. if (res == -1) {
  378. goto error_exit;
  379. }
  380. for (;;) {
  381. timeout = timerlist_timeout_msec (&poll_instance->timerlist);
  382. retry_poll:
  383. res = poll (poll_instance->ufds, poll_instance->nfds, timeout);
  384. if (errno == EINTR && res == -1) {
  385. goto retry_poll;
  386. } else
  387. if (res == -1) {
  388. goto error_exit;
  389. }
  390. for (i = 0; i < poll_instance->nfds; i++) {
  391. if (poll_instance->ufds[i].fd != -1 &&
  392. poll_instance->ufds[i].revents) {
  393. res = poll_instance->dispatch_fns[i] (handle, poll_instance->ufds[i].fd,
  394. poll_instance->ufds[i].revents, poll_instance->data[i]);
  395. /*
  396. * Remove dispatch functions that return -1
  397. */
  398. if (res == -1) {
  399. poll_instance->ufds[i].fd = -1; /* empty entry */
  400. }
  401. }
  402. }
  403. timerlist_expire (&poll_instance->timerlist);
  404. } /* for (;;) */
  405. error_exit:
  406. return (-1);
  407. }
  408. int poll_stop (
  409. poll_handle handle);