coropoll.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  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. retry_write:
  227. if (write (poll_instance->pipefds[1], &buf, 1) < 0 && errno == EINTR )
  228. goto retry_write;
  229. }
  230. goto error_put;
  231. }
  232. }
  233. res = -EBADF;
  234. error_put:
  235. hdb_handle_put (&poll_instance_database, handle);
  236. error_exit:
  237. return (res);
  238. }
  239. int poll_dispatch_delete (
  240. hdb_handle_t handle,
  241. int fd)
  242. {
  243. struct poll_instance *poll_instance;
  244. int i;
  245. int res = 0;
  246. res = hdb_handle_get (&poll_instance_database, handle,
  247. (void *)&poll_instance);
  248. if (res != 0) {
  249. res = -ENOENT;
  250. goto error_exit;
  251. }
  252. /*
  253. * Find dispatch fd to delete
  254. */
  255. res = -EBADF;
  256. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  257. if (poll_instance->poll_entries[i].ufd.fd == fd) {
  258. poll_instance->ufds[i].fd = -1;
  259. poll_instance->poll_entries[i].ufd.fd = -1;
  260. poll_instance->poll_entries[i].ufd.revents = 0;
  261. res = 0;
  262. break;
  263. }
  264. }
  265. hdb_handle_put (&poll_instance_database, handle);
  266. error_exit:
  267. return (res);
  268. }
  269. int poll_timer_add (
  270. hdb_handle_t handle,
  271. int msec_duration, void *data,
  272. void (*timer_fn) (void *data),
  273. poll_timer_handle *timer_handle_out)
  274. {
  275. struct poll_instance *poll_instance;
  276. int res = 0;
  277. if (timer_handle_out == NULL) {
  278. res = -ENOENT;
  279. goto error_exit;
  280. }
  281. res = hdb_handle_get (&poll_instance_database, handle,
  282. (void *)&poll_instance);
  283. if (res != 0) {
  284. res = -ENOENT;
  285. goto error_exit;
  286. }
  287. timerlist_add_duration (&poll_instance->timerlist,
  288. timer_fn, data, ((unsigned long long)msec_duration) * 1000000ULL, timer_handle_out);
  289. hdb_handle_put (&poll_instance_database, handle);
  290. error_exit:
  291. return (res);
  292. }
  293. int poll_timer_delete (
  294. hdb_handle_t handle,
  295. poll_timer_handle th)
  296. {
  297. struct poll_instance *poll_instance;
  298. int res = 0;
  299. if (th == 0) {
  300. return (0);
  301. }
  302. res = hdb_handle_get (&poll_instance_database, handle,
  303. (void *)&poll_instance);
  304. if (res != 0) {
  305. res = -ENOENT;
  306. goto error_exit;
  307. }
  308. timerlist_del (&poll_instance->timerlist, (void *)th);
  309. hdb_handle_put (&poll_instance_database, handle);
  310. error_exit:
  311. return (res);
  312. }
  313. int poll_stop (
  314. hdb_handle_t handle)
  315. {
  316. struct poll_instance *poll_instance;
  317. unsigned int res;
  318. res = hdb_handle_get (&poll_instance_database, handle,
  319. (void *)&poll_instance);
  320. if (res != 0) {
  321. res = -ENOENT;
  322. goto error_exit;
  323. }
  324. poll_instance->stop_requested = 1;
  325. hdb_handle_put (&poll_instance_database, handle);
  326. error_exit:
  327. return (res);
  328. }
  329. int poll_low_fds_event_set(
  330. hdb_handle_t handle,
  331. poll_low_fds_event_fn fn)
  332. {
  333. struct poll_instance *poll_instance;
  334. if (hdb_handle_get (&poll_instance_database, handle,
  335. (void *)&poll_instance) != 0) {
  336. return -ENOENT;
  337. }
  338. poll_instance->low_fds_event_fn = fn;
  339. hdb_handle_put (&poll_instance_database, handle);
  340. return 0;
  341. }
  342. /* logs, std(in|out|err), pipe */
  343. #define POLL_FDS_USED_MISC 50
  344. static void poll_fds_usage_check(struct poll_instance *poll_instance)
  345. {
  346. struct rlimit lim;
  347. static int32_t socks_limit = 0;
  348. int32_t send_event = 0;
  349. int32_t socks_used = 0;
  350. int32_t socks_avail = 0;
  351. int32_t i;
  352. if (socks_limit == 0) {
  353. if (getrlimit(RLIMIT_NOFILE, &lim) == -1) {
  354. char error_str[100];
  355. strerror_r(errno, error_str, 100);
  356. printf("getrlimit: %s\n", error_str);
  357. return;
  358. }
  359. socks_limit = lim.rlim_cur;
  360. socks_limit -= POLL_FDS_USED_MISC;
  361. if (socks_limit < 0) {
  362. socks_limit = 0;
  363. }
  364. }
  365. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  366. if (poll_instance->poll_entries[i].ufd.fd != -1) {
  367. socks_used++;
  368. }
  369. }
  370. socks_avail = socks_limit - socks_used;
  371. if (socks_avail < 0) {
  372. socks_avail = 0;
  373. }
  374. send_event = 0;
  375. if (poll_instance->not_enough_fds) {
  376. if (socks_avail > 2) {
  377. poll_instance->not_enough_fds = 0;
  378. send_event = 1;
  379. }
  380. } else {
  381. if (socks_avail <= 1) {
  382. poll_instance->not_enough_fds = 1;
  383. send_event = 1;
  384. }
  385. }
  386. if (send_event) {
  387. poll_instance->low_fds_event_fn(poll_instance->not_enough_fds,
  388. socks_avail);
  389. }
  390. }
  391. int poll_run (
  392. hdb_handle_t handle)
  393. {
  394. struct poll_instance *poll_instance;
  395. int i;
  396. unsigned long long expire_timeout_msec = -1;
  397. int res;
  398. int poll_entry_count;
  399. res = hdb_handle_get (&poll_instance_database, handle,
  400. (void *)&poll_instance);
  401. if (res != 0) {
  402. goto error_exit;
  403. }
  404. for (;;) {
  405. rebuild_poll:
  406. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  407. memcpy (&poll_instance->ufds[i],
  408. &poll_instance->poll_entries[i].ufd,
  409. sizeof (struct pollfd));
  410. }
  411. poll_fds_usage_check(poll_instance);
  412. expire_timeout_msec = timerlist_msec_duration_to_expire (&poll_instance->timerlist);
  413. if (expire_timeout_msec != -1 && expire_timeout_msec > 0xFFFFFFFF) {
  414. expire_timeout_msec = 0xFFFFFFFE;
  415. }
  416. retry_poll:
  417. res = poll (poll_instance->ufds,
  418. poll_instance->poll_entry_count, expire_timeout_msec);
  419. if (poll_instance->stop_requested) {
  420. return (0);
  421. }
  422. if (errno == EINTR && res == -1) {
  423. goto retry_poll;
  424. } else
  425. if (res == -1) {
  426. goto error_exit;
  427. }
  428. if (poll_instance->ufds[0].revents) {
  429. char buf;
  430. retry_read:
  431. if (read (poll_instance->ufds[0].fd, &buf, 1) < 0 && errno == EINTR)
  432. goto retry_read;
  433. goto rebuild_poll;
  434. }
  435. poll_entry_count = poll_instance->poll_entry_count;
  436. for (i = 0; i < poll_entry_count; i++) {
  437. if (poll_instance->ufds[i].fd != -1 &&
  438. poll_instance->ufds[i].revents) {
  439. res = poll_instance->poll_entries[i].dispatch_fn (handle,
  440. poll_instance->ufds[i].fd,
  441. poll_instance->ufds[i].revents,
  442. poll_instance->poll_entries[i].data);
  443. /*
  444. * Remove dispatch functions that return -1
  445. */
  446. if (res == -1) {
  447. poll_instance->poll_entries[i].ufd.fd = -1; /* empty entry */
  448. }
  449. }
  450. }
  451. timerlist_expire (&poll_instance->timerlist);
  452. } /* for (;;) */
  453. hdb_handle_put (&poll_instance_database, handle);
  454. error_exit:
  455. return (-1);
  456. }
  457. #ifdef COMPILE_OUT
  458. void poll_print_state (
  459. hdb_handle_t handle,
  460. int fd)
  461. {
  462. struct poll_instance *poll_instance;
  463. int i;
  464. int res = 0;
  465. res = hdb_handle_get (&poll_instance_database, handle,
  466. (void *)&poll_instance);
  467. if (res != 0) {
  468. res = -ENOENT;
  469. exit (1);
  470. }
  471. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  472. if (poll_instance->poll_entries[i].ufd.fd == fd) {
  473. printf ("fd %d\n", poll_instance->poll_entries[i].ufd.fd);
  474. printf ("events %d\n", poll_instance->poll_entries[i].ufd.events);
  475. printf ("dispatch_fn %p\n", poll_instance->poll_entries[i].dispatch_fn);
  476. }
  477. }
  478. }
  479. #endif