4
0

coropoll.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  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. #include "util.h"
  50. typedef int (*dispatch_fn_t) (hdb_handle_t hdb_handle, int fd, int revents, void *data);
  51. struct poll_entry {
  52. struct pollfd ufd;
  53. dispatch_fn_t dispatch_fn;
  54. void *data;
  55. };
  56. struct poll_instance {
  57. struct poll_entry *poll_entries;
  58. struct pollfd *ufds;
  59. int poll_entry_count;
  60. struct timerlist timerlist;
  61. int stop_requested;
  62. int pipefds[2];
  63. poll_low_fds_event_fn low_fds_event_fn;
  64. int32_t not_enough_fds;
  65. };
  66. DECLARE_HDB_DATABASE (poll_instance_database,NULL);
  67. static int dummy_dispatch_fn (hdb_handle_t handle, int fd, int revents, void *data) {
  68. return (0);
  69. }
  70. hdb_handle_t poll_create (void)
  71. {
  72. hdb_handle_t handle;
  73. struct poll_instance *poll_instance;
  74. unsigned int res;
  75. res = hdb_handle_create (&poll_instance_database,
  76. sizeof (struct poll_instance), &handle);
  77. if (res != 0) {
  78. goto error_exit;
  79. }
  80. res = hdb_handle_get (&poll_instance_database, handle,
  81. (void *)&poll_instance);
  82. if (res != 0) {
  83. goto error_destroy;
  84. }
  85. poll_instance->poll_entries = 0;
  86. poll_instance->ufds = 0;
  87. poll_instance->poll_entry_count = 0;
  88. poll_instance->stop_requested = 0;
  89. poll_instance->not_enough_fds = 0;
  90. timerlist_init (&poll_instance->timerlist);
  91. res = pipe (poll_instance->pipefds);
  92. if (res != 0) {
  93. goto error_destroy;
  94. }
  95. /*
  96. * Allow changes in modify to propogate into new poll instance
  97. */
  98. res = poll_dispatch_add (
  99. handle,
  100. poll_instance->pipefds[0],
  101. POLLIN,
  102. NULL,
  103. dummy_dispatch_fn);
  104. if (res != 0) {
  105. goto error_destroy;
  106. }
  107. return (handle);
  108. error_destroy:
  109. hdb_handle_destroy (&poll_instance_database, handle);
  110. error_exit:
  111. return (-1);
  112. }
  113. int poll_destroy (hdb_handle_t handle)
  114. {
  115. struct poll_instance *poll_instance;
  116. int res = 0;
  117. res = hdb_handle_get (&poll_instance_database, handle,
  118. (void *)&poll_instance);
  119. if (res != 0) {
  120. res = -ENOENT;
  121. goto error_exit;
  122. }
  123. free (poll_instance->poll_entries);
  124. free (poll_instance->ufds);
  125. hdb_handle_destroy (&poll_instance_database, handle);
  126. hdb_handle_put (&poll_instance_database, handle);
  127. error_exit:
  128. return (res);
  129. }
  130. int poll_dispatch_add (
  131. hdb_handle_t handle,
  132. int fd,
  133. int events,
  134. void *data,
  135. int (*dispatch_fn) (
  136. hdb_handle_t hdb_handle_t,
  137. int fd,
  138. int revents,
  139. void *data))
  140. {
  141. struct poll_instance *poll_instance;
  142. struct poll_entry *poll_entries;
  143. struct pollfd *ufds;
  144. int found = 0;
  145. int install_pos;
  146. int res = 0;
  147. res = hdb_handle_get (&poll_instance_database, handle,
  148. (void *)&poll_instance);
  149. if (res != 0) {
  150. res = -ENOENT;
  151. goto error_exit;
  152. }
  153. for (found = 0, install_pos = 0; install_pos < poll_instance->poll_entry_count; install_pos++) {
  154. if (poll_instance->poll_entries[install_pos].ufd.fd == -1) {
  155. found = 1;
  156. break;
  157. }
  158. }
  159. if (found == 0) {
  160. /*
  161. * Grow pollfd list
  162. */
  163. poll_entries = (struct poll_entry *)realloc (poll_instance->poll_entries,
  164. (poll_instance->poll_entry_count + 1) *
  165. sizeof (struct poll_entry));
  166. if (poll_entries == NULL) {
  167. res = -ENOMEM;
  168. goto error_put;
  169. }
  170. poll_instance->poll_entries = poll_entries;
  171. ufds = (struct pollfd *)realloc (poll_instance->ufds,
  172. (poll_instance->poll_entry_count + 1) *
  173. sizeof (struct pollfd));
  174. if (ufds == NULL) {
  175. res = -ENOMEM;
  176. goto error_put;
  177. }
  178. poll_instance->ufds = ufds;
  179. poll_instance->poll_entry_count += 1;
  180. install_pos = poll_instance->poll_entry_count - 1;
  181. }
  182. /*
  183. * Install new dispatch handler
  184. */
  185. poll_instance->poll_entries[install_pos].ufd.fd = fd;
  186. poll_instance->poll_entries[install_pos].ufd.events = events;
  187. poll_instance->poll_entries[install_pos].ufd.revents = 0;
  188. poll_instance->poll_entries[install_pos].dispatch_fn = dispatch_fn;
  189. poll_instance->poll_entries[install_pos].data = data;
  190. error_put:
  191. hdb_handle_put (&poll_instance_database, handle);
  192. error_exit:
  193. return (res);
  194. }
  195. int poll_dispatch_modify (
  196. hdb_handle_t handle,
  197. int fd,
  198. int events,
  199. int (*dispatch_fn) (
  200. hdb_handle_t hdb_handle_t,
  201. int fd,
  202. int revents,
  203. void *data))
  204. {
  205. struct poll_instance *poll_instance;
  206. int i;
  207. int res = 0;
  208. res = hdb_handle_get (&poll_instance_database, handle,
  209. (void *)&poll_instance);
  210. if (res != 0) {
  211. res = -ENOENT;
  212. goto error_exit;
  213. }
  214. /*
  215. * Find file descriptor to modify events and dispatch function
  216. */
  217. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  218. if (poll_instance->poll_entries[i].ufd.fd == fd) {
  219. int change_notify = 0;
  220. if (poll_instance->poll_entries[i].ufd.events != events) {
  221. change_notify = 1;
  222. }
  223. poll_instance->poll_entries[i].ufd.events = events;
  224. poll_instance->poll_entries[i].dispatch_fn = dispatch_fn;
  225. if (change_notify) {
  226. char buf = 1;
  227. retry_write:
  228. if (write (poll_instance->pipefds[1], &buf, 1) < 0 && errno == EINTR )
  229. goto retry_write;
  230. }
  231. goto error_put;
  232. }
  233. }
  234. res = -EBADF;
  235. error_put:
  236. hdb_handle_put (&poll_instance_database, handle);
  237. error_exit:
  238. return (res);
  239. }
  240. int poll_dispatch_delete (
  241. hdb_handle_t handle,
  242. int fd)
  243. {
  244. struct poll_instance *poll_instance;
  245. int i;
  246. int res = 0;
  247. res = hdb_handle_get (&poll_instance_database, handle,
  248. (void *)&poll_instance);
  249. if (res != 0) {
  250. res = -ENOENT;
  251. goto error_exit;
  252. }
  253. /*
  254. * Find dispatch fd to delete
  255. */
  256. res = -EBADF;
  257. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  258. if (poll_instance->poll_entries[i].ufd.fd == fd) {
  259. poll_instance->ufds[i].fd = -1;
  260. poll_instance->poll_entries[i].ufd.fd = -1;
  261. poll_instance->poll_entries[i].ufd.revents = 0;
  262. res = 0;
  263. break;
  264. }
  265. }
  266. hdb_handle_put (&poll_instance_database, handle);
  267. error_exit:
  268. return (res);
  269. }
  270. int poll_timer_add (
  271. hdb_handle_t handle,
  272. int msec_duration, void *data,
  273. void (*timer_fn) (void *data),
  274. poll_timer_handle *timer_handle_out)
  275. {
  276. struct poll_instance *poll_instance;
  277. int res = 0;
  278. if (timer_handle_out == NULL) {
  279. res = -ENOENT;
  280. goto error_exit;
  281. }
  282. res = hdb_handle_get (&poll_instance_database, handle,
  283. (void *)&poll_instance);
  284. if (res != 0) {
  285. res = -ENOENT;
  286. goto error_exit;
  287. }
  288. timerlist_add_duration (&poll_instance->timerlist,
  289. timer_fn, data, ((unsigned long long)msec_duration) * 1000000ULL, timer_handle_out);
  290. hdb_handle_put (&poll_instance_database, handle);
  291. error_exit:
  292. return (res);
  293. }
  294. int poll_timer_delete (
  295. hdb_handle_t handle,
  296. poll_timer_handle th)
  297. {
  298. struct poll_instance *poll_instance;
  299. int res = 0;
  300. if (th == 0) {
  301. return (0);
  302. }
  303. res = hdb_handle_get (&poll_instance_database, handle,
  304. (void *)&poll_instance);
  305. if (res != 0) {
  306. res = -ENOENT;
  307. goto error_exit;
  308. }
  309. timerlist_del (&poll_instance->timerlist, (void *)th);
  310. hdb_handle_put (&poll_instance_database, handle);
  311. error_exit:
  312. return (res);
  313. }
  314. int poll_stop (
  315. hdb_handle_t handle)
  316. {
  317. struct poll_instance *poll_instance;
  318. unsigned int res;
  319. res = hdb_handle_get (&poll_instance_database, handle,
  320. (void *)&poll_instance);
  321. if (res != 0) {
  322. res = -ENOENT;
  323. goto error_exit;
  324. }
  325. poll_instance->stop_requested = 1;
  326. hdb_handle_put (&poll_instance_database, handle);
  327. error_exit:
  328. return (res);
  329. }
  330. int poll_low_fds_event_set(
  331. hdb_handle_t handle,
  332. poll_low_fds_event_fn fn)
  333. {
  334. struct poll_instance *poll_instance;
  335. if (hdb_handle_get (&poll_instance_database, handle,
  336. (void *)&poll_instance) != 0) {
  337. return -ENOENT;
  338. }
  339. poll_instance->low_fds_event_fn = fn;
  340. hdb_handle_put (&poll_instance_database, handle);
  341. return 0;
  342. }
  343. /* logs, std(in|out|err), pipe */
  344. #define POLL_FDS_USED_MISC 50
  345. static void poll_fds_usage_check(struct poll_instance *poll_instance)
  346. {
  347. struct rlimit lim;
  348. static int32_t socks_limit = 0;
  349. int32_t send_event = 0;
  350. int32_t socks_used = 0;
  351. int32_t socks_avail = 0;
  352. int32_t i;
  353. if (socks_limit == 0) {
  354. if (getrlimit(RLIMIT_NOFILE, &lim) == -1) {
  355. perror("getrlimit() failed");
  356. return;
  357. }
  358. socks_limit = lim.rlim_cur;
  359. socks_limit -= POLL_FDS_USED_MISC;
  360. if (socks_limit < 0) {
  361. socks_limit = 0;
  362. }
  363. }
  364. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  365. if (poll_instance->poll_entries[i].ufd.fd != -1) {
  366. socks_used++;
  367. }
  368. }
  369. socks_avail = socks_limit - socks_used;
  370. if (socks_avail < 0) {
  371. socks_avail = 0;
  372. }
  373. send_event = 0;
  374. if (poll_instance->not_enough_fds) {
  375. if (socks_avail > 2) {
  376. poll_instance->not_enough_fds = 0;
  377. send_event = 1;
  378. }
  379. } else {
  380. if (socks_avail <= 1) {
  381. poll_instance->not_enough_fds = 1;
  382. send_event = 1;
  383. }
  384. }
  385. if (send_event) {
  386. poll_instance->low_fds_event_fn(poll_instance->not_enough_fds,
  387. socks_avail);
  388. }
  389. }
  390. int poll_run (
  391. hdb_handle_t handle)
  392. {
  393. struct poll_instance *poll_instance;
  394. int i;
  395. unsigned long long expire_timeout_msec = -1;
  396. int res;
  397. int poll_entry_count;
  398. res = hdb_handle_get (&poll_instance_database, handle,
  399. (void *)&poll_instance);
  400. if (res != 0) {
  401. goto error_exit;
  402. }
  403. for (;;) {
  404. rebuild_poll:
  405. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  406. memcpy (&poll_instance->ufds[i],
  407. &poll_instance->poll_entries[i].ufd,
  408. sizeof (struct pollfd));
  409. }
  410. poll_fds_usage_check(poll_instance);
  411. expire_timeout_msec = timerlist_msec_duration_to_expire (&poll_instance->timerlist);
  412. if (expire_timeout_msec != -1 && expire_timeout_msec > 0xFFFFFFFF) {
  413. expire_timeout_msec = 0xFFFFFFFE;
  414. }
  415. retry_poll:
  416. res = poll (poll_instance->ufds,
  417. poll_instance->poll_entry_count, expire_timeout_msec);
  418. if (poll_instance->stop_requested) {
  419. return (0);
  420. }
  421. if (errno == EINTR && res == -1) {
  422. goto retry_poll;
  423. } else
  424. if (res == -1) {
  425. goto error_exit;
  426. }
  427. if (poll_instance->ufds[0].revents) {
  428. char buf;
  429. retry_read:
  430. if (read (poll_instance->ufds[0].fd, &buf, 1) < 0 && errno == EINTR)
  431. goto retry_read;
  432. goto rebuild_poll;
  433. }
  434. poll_entry_count = poll_instance->poll_entry_count;
  435. for (i = 0; i < poll_entry_count; i++) {
  436. if (poll_instance->ufds[i].fd != -1 &&
  437. poll_instance->ufds[i].revents) {
  438. res = poll_instance->poll_entries[i].dispatch_fn (handle,
  439. poll_instance->ufds[i].fd,
  440. poll_instance->ufds[i].revents,
  441. poll_instance->poll_entries[i].data);
  442. /*
  443. * Remove dispatch functions that return -1
  444. */
  445. if (res == -1) {
  446. poll_instance->poll_entries[i].ufd.fd = -1; /* empty entry */
  447. }
  448. }
  449. }
  450. timerlist_expire (&poll_instance->timerlist);
  451. } /* for (;;) */
  452. hdb_handle_put (&poll_instance_database, handle);
  453. error_exit:
  454. return (-1);
  455. }
  456. #ifdef COMPILE_OUT
  457. void poll_print_state (
  458. hdb_handle_t handle,
  459. int fd)
  460. {
  461. struct poll_instance *poll_instance;
  462. int i;
  463. int res = 0;
  464. res = hdb_handle_get (&poll_instance_database, handle,
  465. (void *)&poll_instance);
  466. if (res != 0) {
  467. res = -ENOENT;
  468. exit (1);
  469. }
  470. for (i = 0; i < poll_instance->poll_entry_count; i++) {
  471. if (poll_instance->poll_entries[i].ufd.fd == fd) {
  472. printf ("fd %d\n", poll_instance->poll_entries[i].ufd.fd);
  473. printf ("events %d\n", poll_instance->poll_entries[i].ufd.events);
  474. printf ("dispatch_fn %p\n", poll_instance->poll_entries[i].dispatch_fn);
  475. }
  476. }
  477. }
  478. #endif