coropoll.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. /*
  2. * Copyright (c) 2003-2004 MontaVista Software, Inc.
  3. * Copyright (c) 2006-2009 Red Hat, Inc.
  4. *
  5. * All rights reserved.
  6. *
  7. * Author: Steven Dake (sdake@redhat.com)
  8. *
  9. * This software licensed under BSD license, the text of which follows:
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions are met:
  13. *
  14. * - Redistributions of source code must retain the above copyright notice,
  15. * this list of conditions and the following disclaimer.
  16. * - Redistributions in binary form must reproduce the above copyright notice,
  17. * this list of conditions and the following disclaimer in the documentation
  18. * and/or other materials provided with the distribution.
  19. * - Neither the name of the MontaVista Software, Inc. nor the names of its
  20. * contributors may be used to endorse or promote products derived from this
  21. * software without specific prior written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  24. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  27. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  28. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  29. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  30. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  31. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  32. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  33. * THE POSSIBILITY OF SUCH DAMAGE.
  34. */
  35. #include <config.h>
  36. #include <errno.h>
  37. #include <pthread.h>
  38. #include <sys/poll.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <stdio.h>
  42. #include <unistd.h>
  43. #include <sys/time.h>
  44. #include <sys/resource.h>
  45. #include <corosync/hdb.h>
  46. #include <corosync/totem/coropoll.h>
  47. #include <corosync/list.h>
  48. #include "tlist.h"
  49. typedef int (*dispatch_fn_t) (hdb_handle_t hdb_handle, int fd, int revents, void *data);
  50. struct poll_entry {
  51. struct pollfd ufd;
  52. dispatch_fn_t dispatch_fn;
  53. void *data;
  54. };
  55. struct poll_instance {
  56. struct poll_entry *poll_entries;
  57. struct pollfd *ufds;
  58. int poll_entry_count;
  59. struct timerlist timerlist;
  60. int stop_requested;
  61. int pipefds[2];
  62. poll_low_fds_event_fn low_fds_event_fn;
  63. int32_t not_enough_fds;
  64. };
  65. DECLARE_HDB_DATABASE (poll_instance_database,NULL);
  66. static int dummy_dispatch_fn (hdb_handle_t handle, int fd, int revents, void *data) {
  67. return (0);
  68. }
  69. hdb_handle_t poll_create (void)
  70. {
  71. hdb_handle_t handle;
  72. struct poll_instance *poll_instance;
  73. unsigned int res;
  74. res = hdb_handle_create (&poll_instance_database,
  75. sizeof (struct poll_instance), &handle);
  76. if (res != 0) {
  77. goto error_exit;
  78. }
  79. res = hdb_handle_get (&poll_instance_database, handle,
  80. (void *)&poll_instance);
  81. if (res != 0) {
  82. goto error_destroy;
  83. }
  84. poll_instance->poll_entries = 0;
  85. poll_instance->ufds = 0;
  86. poll_instance->poll_entry_count = 0;
  87. poll_instance->stop_requested = 0;
  88. poll_instance->not_enough_fds = 0;
  89. timerlist_init (&poll_instance->timerlist);
  90. res = pipe (poll_instance->pipefds);
  91. if (res != 0) {
  92. goto error_destroy;
  93. }
  94. /*
  95. * Allow changes in modify to propogate into new poll instance
  96. */
  97. res = poll_dispatch_add (
  98. handle,
  99. poll_instance->pipefds[0],
  100. POLLIN,
  101. NULL,
  102. dummy_dispatch_fn);
  103. if (res != 0) {
  104. goto error_destroy;
  105. }
  106. return (handle);
  107. error_destroy:
  108. hdb_handle_destroy (&poll_instance_database, handle);
  109. error_exit:
  110. return (-1);
  111. }
  112. int poll_destroy (hdb_handle_t handle)
  113. {
  114. struct poll_instance *poll_instance;
  115. int res = 0;
  116. res = hdb_handle_get (&poll_instance_database, handle,
  117. (void *)&poll_instance);
  118. if (res != 0) {
  119. res = -ENOENT;
  120. goto error_exit;
  121. }
  122. free (poll_instance->poll_entries);
  123. free (poll_instance->ufds);
  124. hdb_handle_destroy (&poll_instance_database, handle);
  125. hdb_handle_put (&poll_instance_database, handle);
  126. error_exit:
  127. return (res);
  128. }
  129. int poll_dispatch_add (
  130. hdb_handle_t handle,
  131. int fd,
  132. int events,
  133. void *data,
  134. int (*dispatch_fn) (
  135. hdb_handle_t hdb_handle_t,
  136. int fd,
  137. int revents,
  138. void *data))
  139. {
  140. struct poll_instance *poll_instance;
  141. struct poll_entry *poll_entries;
  142. struct pollfd *ufds;
  143. int found = 0;
  144. int install_pos;
  145. int res = 0;
  146. res = hdb_handle_get (&poll_instance_database, handle,
  147. (void *)&poll_instance);
  148. if (res != 0) {
  149. res = -ENOENT;
  150. goto error_exit;
  151. }
  152. for (found = 0, install_pos = 0; install_pos < poll_instance->poll_entry_count; install_pos++) {
  153. if (poll_instance->poll_entries[install_pos].ufd.fd == -1) {
  154. found = 1;
  155. break;
  156. }
  157. }
  158. if (found == 0) {
  159. /*
  160. * Grow pollfd list
  161. */
  162. poll_entries = (struct poll_entry *)realloc (poll_instance->poll_entries,
  163. (poll_instance->poll_entry_count + 1) *
  164. sizeof (struct poll_entry));
  165. if (poll_entries == NULL) {
  166. res = -ENOMEM;
  167. goto error_put;
  168. }
  169. poll_instance->poll_entries = poll_entries;
  170. ufds = (struct pollfd *)realloc (poll_instance->ufds,
  171. (poll_instance->poll_entry_count + 1) *
  172. sizeof (struct pollfd));
  173. if (ufds == NULL) {
  174. res = -ENOMEM;
  175. goto error_put;
  176. }
  177. poll_instance->ufds = ufds;
  178. poll_instance->poll_entry_count += 1;
  179. install_pos = poll_instance->poll_entry_count - 1;
  180. }
  181. /*
  182. * Install new dispatch handler
  183. */
  184. poll_instance->poll_entries[install_pos].ufd.fd = fd;
  185. poll_instance->poll_entries[install_pos].ufd.events = events;
  186. poll_instance->poll_entries[install_pos].ufd.revents = 0;
  187. poll_instance->poll_entries[install_pos].dispatch_fn = dispatch_fn;
  188. poll_instance->poll_entries[install_pos].data = data;
  189. error_put:
  190. hdb_handle_put (&poll_instance_database, handle);
  191. error_exit:
  192. return (res);
  193. }
  194. int poll_dispatch_modify (
  195. hdb_handle_t handle,
  196. int fd,
  197. int events,
  198. int (*dispatch_fn) (
  199. hdb_handle_t hdb_handle_t,
  200. int fd,
  201. int revents,
  202. void *data))
  203. {
  204. struct poll_instance *poll_instance;
  205. int i;
  206. int res = 0;
  207. res = hdb_handle_get (&poll_instance_database, handle,
  208. (void *)&poll_instance);
  209. if (res != 0) {
  210. res = -ENOENT;
  211. goto error_exit;
  212. }
  213. /*
  214. * Find file descriptor to modify events and dispatch function
  215. */
  216. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  217. if (poll_instance->poll_entries[i].ufd.fd == fd) {
  218. int change_notify = 0;
  219. if (poll_instance->poll_entries[i].ufd.events != events) {
  220. change_notify = 1;
  221. }
  222. poll_instance->poll_entries[i].ufd.events = events;
  223. poll_instance->poll_entries[i].dispatch_fn = dispatch_fn;
  224. if (change_notify) {
  225. char buf = 1;
  226. write (poll_instance->pipefds[1], &buf, 1);
  227. }
  228. goto error_put;
  229. }
  230. }
  231. res = -EBADF;
  232. error_put:
  233. hdb_handle_put (&poll_instance_database, handle);
  234. error_exit:
  235. return (res);
  236. }
  237. int poll_dispatch_delete (
  238. hdb_handle_t handle,
  239. int fd)
  240. {
  241. struct poll_instance *poll_instance;
  242. int i;
  243. int res = 0;
  244. res = hdb_handle_get (&poll_instance_database, handle,
  245. (void *)&poll_instance);
  246. if (res != 0) {
  247. res = -ENOENT;
  248. goto error_exit;
  249. }
  250. /*
  251. * Find dispatch fd to delete
  252. */
  253. res = -EBADF;
  254. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  255. if (poll_instance->poll_entries[i].ufd.fd == fd) {
  256. poll_instance->ufds[i].fd = -1;
  257. poll_instance->poll_entries[i].ufd.fd = -1;
  258. poll_instance->poll_entries[i].ufd.revents = 0;
  259. res = 0;
  260. break;
  261. }
  262. }
  263. hdb_handle_put (&poll_instance_database, handle);
  264. error_exit:
  265. return (res);
  266. }
  267. int poll_timer_add (
  268. hdb_handle_t handle,
  269. int msec_duration, void *data,
  270. void (*timer_fn) (void *data),
  271. poll_timer_handle *timer_handle_out)
  272. {
  273. struct poll_instance *poll_instance;
  274. int res = 0;
  275. if (timer_handle_out == NULL) {
  276. res = -ENOENT;
  277. goto error_exit;
  278. }
  279. res = hdb_handle_get (&poll_instance_database, handle,
  280. (void *)&poll_instance);
  281. if (res != 0) {
  282. res = -ENOENT;
  283. goto error_exit;
  284. }
  285. timerlist_add_duration (&poll_instance->timerlist,
  286. timer_fn, data, ((unsigned long long)msec_duration) * 1000000ULL, timer_handle_out);
  287. hdb_handle_put (&poll_instance_database, handle);
  288. error_exit:
  289. return (res);
  290. }
  291. int poll_timer_delete (
  292. hdb_handle_t handle,
  293. poll_timer_handle th)
  294. {
  295. struct poll_instance *poll_instance;
  296. int res = 0;
  297. if (th == 0) {
  298. return (0);
  299. }
  300. res = hdb_handle_get (&poll_instance_database, handle,
  301. (void *)&poll_instance);
  302. if (res != 0) {
  303. res = -ENOENT;
  304. goto error_exit;
  305. }
  306. timerlist_del (&poll_instance->timerlist, (void *)th);
  307. hdb_handle_put (&poll_instance_database, handle);
  308. error_exit:
  309. return (res);
  310. }
  311. int poll_stop (
  312. hdb_handle_t handle)
  313. {
  314. struct poll_instance *poll_instance;
  315. unsigned int res;
  316. res = hdb_handle_get (&poll_instance_database, handle,
  317. (void *)&poll_instance);
  318. if (res != 0) {
  319. res = -ENOENT;
  320. goto error_exit;
  321. }
  322. poll_instance->stop_requested = 1;
  323. hdb_handle_put (&poll_instance_database, handle);
  324. error_exit:
  325. return (res);
  326. }
  327. int poll_low_fds_event_set(
  328. hdb_handle_t handle,
  329. poll_low_fds_event_fn fn)
  330. {
  331. struct poll_instance *poll_instance;
  332. if (hdb_handle_get (&poll_instance_database, handle,
  333. (void *)&poll_instance) != 0) {
  334. return -ENOENT;
  335. }
  336. poll_instance->low_fds_event_fn = fn;
  337. hdb_handle_put (&poll_instance_database, handle);
  338. return 0;
  339. }
  340. /* logs, std(in|out|err), pipe */
  341. #define POLL_FDS_USED_MISC 50
  342. static void poll_fds_usage_check(struct poll_instance *poll_instance)
  343. {
  344. struct rlimit lim;
  345. static int32_t socks_limit = 0;
  346. int32_t send_event = 0;
  347. int32_t socks_used = 0;
  348. int32_t socks_avail = 0;
  349. int32_t i;
  350. if (socks_limit == 0) {
  351. if (getrlimit(RLIMIT_NOFILE, &lim) == -1) {
  352. char error_str[100];
  353. strerror_r(errno, error_str, 100);
  354. printf("getrlimit: %s\n", error_str);
  355. return;
  356. }
  357. socks_limit = lim.rlim_cur;
  358. socks_limit -= POLL_FDS_USED_MISC;
  359. if (socks_limit < 0) {
  360. socks_limit = 0;
  361. }
  362. }
  363. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  364. if (poll_instance->poll_entries[i].ufd.fd != -1) {
  365. socks_used++;
  366. }
  367. }
  368. socks_avail = socks_limit - socks_used;
  369. if (socks_avail < 0) {
  370. socks_avail = 0;
  371. }
  372. send_event = 0;
  373. if (poll_instance->not_enough_fds) {
  374. if (socks_avail > 2) {
  375. poll_instance->not_enough_fds = 0;
  376. send_event = 1;
  377. }
  378. } else {
  379. if (socks_avail <= 1) {
  380. poll_instance->not_enough_fds = 1;
  381. send_event = 1;
  382. }
  383. }
  384. if (send_event) {
  385. poll_instance->low_fds_event_fn(poll_instance->not_enough_fds,
  386. socks_avail);
  387. }
  388. }
  389. int poll_run (
  390. hdb_handle_t handle)
  391. {
  392. struct poll_instance *poll_instance;
  393. int i;
  394. unsigned long long expire_timeout_msec = -1;
  395. int res;
  396. int poll_entry_count;
  397. res = hdb_handle_get (&poll_instance_database, handle,
  398. (void *)&poll_instance);
  399. if (res != 0) {
  400. goto error_exit;
  401. }
  402. for (;;) {
  403. rebuild_poll:
  404. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  405. memcpy (&poll_instance->ufds[i],
  406. &poll_instance->poll_entries[i].ufd,
  407. sizeof (struct pollfd));
  408. }
  409. poll_fds_usage_check(poll_instance);
  410. expire_timeout_msec = timerlist_msec_duration_to_expire (&poll_instance->timerlist);
  411. if (expire_timeout_msec != -1 && expire_timeout_msec > 0xFFFFFFFF) {
  412. expire_timeout_msec = 0xFFFFFFFE;
  413. }
  414. retry_poll:
  415. res = poll (poll_instance->ufds,
  416. poll_instance->poll_entry_count, expire_timeout_msec);
  417. if (poll_instance->stop_requested) {
  418. return (0);
  419. }
  420. if (errno == EINTR && res == -1) {
  421. goto retry_poll;
  422. } else
  423. if (res == -1) {
  424. goto error_exit;
  425. }
  426. if (poll_instance->ufds[0].revents) {
  427. char buf;
  428. read (poll_instance->ufds[0].fd, &buf, 1);
  429. goto rebuild_poll;
  430. }
  431. poll_entry_count = poll_instance->poll_entry_count;
  432. for (i = 0; i < poll_entry_count; i++) {
  433. if (poll_instance->ufds[i].fd != -1 &&
  434. poll_instance->ufds[i].revents) {
  435. res = poll_instance->poll_entries[i].dispatch_fn (handle,
  436. poll_instance->ufds[i].fd,
  437. poll_instance->ufds[i].revents,
  438. poll_instance->poll_entries[i].data);
  439. /*
  440. * Remove dispatch functions that return -1
  441. */
  442. if (res == -1) {
  443. poll_instance->poll_entries[i].ufd.fd = -1; /* empty entry */
  444. }
  445. }
  446. }
  447. timerlist_expire (&poll_instance->timerlist);
  448. } /* for (;;) */
  449. hdb_handle_put (&poll_instance_database, handle);
  450. error_exit:
  451. return (-1);
  452. }
  453. #ifdef COMPILE_OUT
  454. void poll_print_state (
  455. hdb_handle_t handle,
  456. int fd)
  457. {
  458. struct poll_instance *poll_instance;
  459. int i;
  460. int res = 0;
  461. res = hdb_handle_get (&poll_instance_database, handle,
  462. (void *)&poll_instance);
  463. if (res != 0) {
  464. res = -ENOENT;
  465. exit (1);
  466. }
  467. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  468. if (poll_instance->poll_entries[i].ufd.fd == fd) {
  469. printf ("fd %d\n", poll_instance->poll_entries[i].ufd.fd);
  470. printf ("events %d\n", poll_instance->poll_entries[i].ufd.events);
  471. printf ("dispatch_fn %p\n", poll_instance->poll_entries[i].dispatch_fn);
  472. }
  473. }
  474. }
  475. #endif