smarty template cache syncing daemon (PoC)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

311 lines
7.6KB

  1. /***************************************************************************
  2. * Copyright (C) 10/2006 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; either version 2 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  10. * This program is distributed in the hope that it will be useful, *
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13. * GNU General Public License for more details. *
  14. * *
  15. * You should have received a copy of the GNU General Public License *
  16. * along with this program; if not, write to the *
  17. * Free Software Foundation, Inc., *
  18. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  19. ***************************************************************************/
  20. #include <stdlib.h>
  21. #include <unistd.h>
  22. #include <string.h>
  23. #include <sys/time.h>
  24. #include <sys/types.h>
  25. #include "list.h"
  26. #include "logging.h"
  27. #include "event.h"
  28. static LIST_HEAD(readfd_list);
  29. static LIST_HEAD(writefd_list);
  30. static LIST_HEAD(exceptfd_list);
  31. static LIST_HEAD(timeout_list);
  32. struct fd_entry {
  33. struct list_head list;
  34. int fd;
  35. int type;
  36. int (*callback)(int fd, void *privdata);
  37. void *privdata;
  38. };
  39. struct timeout_entry {
  40. struct list_head list;
  41. struct timeval timeout;
  42. struct timeval nextrun;
  43. int (*callback)(void *privdata);
  44. void *privdata;
  45. };
  46. int event_add_fd(int fd, int type, int (*callback)(int fd, void *privdata), void *privdata)
  47. {
  48. if (fd < 0 || fd > FD_SETSIZE)
  49. return -1;
  50. struct fd_entry *entry;
  51. entry = malloc(sizeof(struct fd_entry));
  52. if (entry == NULL) {
  53. log_print(LOG_ERROR, "event_add_fd(): out of memory");
  54. return -1;
  55. }
  56. entry->fd = fd;
  57. entry->type = type;
  58. entry->callback = callback;
  59. entry->privdata = privdata;
  60. switch (type) {
  61. case FD_READ:
  62. list_add_tail(&entry->list, &readfd_list);
  63. break;
  64. case FD_WRITE:
  65. list_add_tail(&entry->list, &writefd_list);
  66. break;
  67. case FD_EXCEPT:
  68. list_add_tail(&entry->list, &exceptfd_list);
  69. break;
  70. default:
  71. log_print(LOG_ERROR, "add_fd(): unknown type");
  72. free(entry);
  73. return -1;
  74. }
  75. return 0;
  76. }
  77. int event_remove_fd(int fd)
  78. {
  79. struct fd_entry *entry, *tmp;
  80. list_for_each_entry_safe(entry, tmp, &readfd_list, list) {
  81. if (entry->fd == fd) {
  82. list_del(&entry->list);
  83. free(entry);
  84. return 0;
  85. }
  86. }
  87. list_for_each_entry_safe(entry, tmp, &writefd_list, list) {
  88. if (entry->fd == fd) {
  89. list_del(&entry->list);
  90. free(entry);
  91. return 0;
  92. }
  93. }
  94. list_for_each_entry_safe(entry, tmp, &exceptfd_list, list) {
  95. if (entry->fd == fd) {
  96. list_del(&entry->list);
  97. free(entry);
  98. return 0;
  99. }
  100. }
  101. return -1;
  102. }
  103. static void calc_nextrun(struct timeval *timeout, struct timeval *nextrun)
  104. {
  105. struct timeval now;
  106. gettimeofday(&now, NULL);
  107. nextrun->tv_usec = now.tv_usec + timeout->tv_usec;
  108. nextrun->tv_sec = now.tv_sec + timeout->tv_sec;
  109. if (nextrun->tv_usec >= 1000000) {
  110. nextrun->tv_usec -= 1000000;
  111. nextrun->tv_sec++;
  112. }
  113. }
  114. static void calc_timeout(struct timeval *timeout, struct timeval *nextrun)
  115. {
  116. struct timeval now;
  117. gettimeofday(&now, NULL);
  118. timeout->tv_usec = nextrun->tv_usec - now.tv_usec;
  119. timeout->tv_sec = nextrun->tv_sec - now.tv_sec;
  120. if (timeout->tv_usec < 0) {
  121. timeout->tv_usec += 1000000;
  122. timeout->tv_sec--;
  123. }
  124. }
  125. static void schedule_nextrun(struct timeout_entry *entry)
  126. {
  127. struct timeout_entry *search;
  128. list_for_each_entry(search, &timeout_list, list) {
  129. if (search->nextrun.tv_sec > entry->nextrun.tv_sec) {
  130. list_add_tail(&entry->list, &search->list);
  131. return;
  132. } else if (search->nextrun.tv_sec == entry->nextrun.tv_sec &&
  133. search->nextrun.tv_usec > entry->nextrun.tv_usec) {
  134. list_add_tail(&entry->list, &search->list);
  135. return;
  136. }
  137. }
  138. list_add_tail(&entry->list, &timeout_list);
  139. }
  140. int event_add_timeout(struct timeval *timeout, int (*callback)(void *privdata), void *privdata)
  141. {
  142. struct timeout_entry *entry;
  143. entry = malloc(sizeof(struct timeout_entry));
  144. if (entry == NULL) {
  145. log_print(LOG_ERROR, "event_add_timeout(): out of memory");
  146. return -1;
  147. }
  148. memcpy(&entry->timeout, timeout, sizeof(entry->timeout));
  149. entry->callback = callback;
  150. entry->privdata = privdata;
  151. calc_nextrun(&entry->timeout, &entry->nextrun);
  152. schedule_nextrun(entry);
  153. return 0;
  154. }
  155. int event_loop(void)
  156. {
  157. while (1) {
  158. fd_set readfds, *readfds_p = NULL;
  159. fd_set writefds, *writefds_p = NULL;
  160. fd_set exceptfds, *exceptfds_p =NULL;
  161. struct timeval timeout, *timeout_p = NULL;
  162. if (!list_empty(&readfd_list)) {
  163. struct fd_entry *entry;
  164. FD_ZERO(&readfds);
  165. list_for_each_entry(entry, &readfd_list, list)
  166. FD_SET(entry->fd, &readfds);
  167. readfds_p = &readfds;
  168. }
  169. if (!list_empty(&writefd_list)) {
  170. struct fd_entry *entry;
  171. FD_ZERO(&writefds);
  172. list_for_each_entry(entry, &writefd_list, list)
  173. FD_SET(entry->fd, &writefds);
  174. writefds_p = &writefds;
  175. }
  176. if (!list_empty(&exceptfd_list)) {
  177. struct fd_entry *entry;
  178. FD_ZERO(&exceptfds);
  179. list_for_each_entry(entry, &exceptfd_list, list)
  180. FD_SET(entry->fd, &exceptfds);
  181. exceptfds_p = &exceptfds;
  182. }
  183. if (!list_empty(&timeout_list)) {
  184. struct timeout_entry *entry, *tmp;
  185. list_for_each_entry_safe(entry, tmp, &timeout_list, list) {
  186. calc_timeout(&timeout, &entry->nextrun);
  187. if (timeout.tv_sec >= 0 && timeout.tv_usec > 0) {
  188. timeout_p = &timeout;
  189. break;
  190. }
  191. // delayed timeout, exec NOW!
  192. list_del(&entry->list);
  193. int ret = entry->callback(entry->privdata);
  194. if (ret == 0) {
  195. calc_nextrun(&entry->timeout, &entry->nextrun);
  196. schedule_nextrun(entry);
  197. } else {
  198. free(entry);
  199. }
  200. }
  201. }
  202. int i = select(FD_SETSIZE, readfds_p, writefds_p, exceptfds_p, timeout_p);
  203. if (i < 0) {
  204. /* On error, -1 is returned, and errno is set
  205. * appropriately; the sets and timeout become
  206. * undefined, so do not rely on their contents
  207. * after an error.
  208. */
  209. continue;
  210. } else if (i == 0 && !list_empty(&timeout_list)) {
  211. struct timeout_entry *entry;
  212. entry = list_entry(timeout_list.next, typeof(*entry), list);
  213. list_del(&entry->list);
  214. int ret = entry->callback(entry->privdata);
  215. if (ret == 0) {
  216. calc_nextrun(&entry->timeout, &entry->nextrun);
  217. schedule_nextrun(entry);
  218. } else {
  219. free(entry);
  220. }
  221. }
  222. if (readfds_p) {
  223. struct fd_entry *entry, *tmp;
  224. list_for_each_entry_safe(entry, tmp, &readfd_list, list) {
  225. if (!FD_ISSET(entry->fd, &readfds))
  226. continue;
  227. if (entry->callback(entry->fd, entry->privdata) != 0) {
  228. list_del(&entry->list);
  229. free(entry);
  230. }
  231. }
  232. }
  233. if (writefds_p) {
  234. struct fd_entry *entry, *tmp;
  235. list_for_each_entry_safe(entry, tmp, &writefd_list, list) {
  236. if (FD_ISSET(entry->fd, &writefds))
  237. continue;
  238. if (entry->callback(entry->fd, entry->privdata) != 0) {
  239. list_del(&entry->list);
  240. free(entry);
  241. }
  242. }
  243. }
  244. if (exceptfds_p) {
  245. struct fd_entry *entry, *tmp;
  246. list_for_each_entry_safe(entry, tmp, &exceptfd_list, list) {
  247. if (FD_ISSET(entry->fd, &exceptfds))
  248. continue;
  249. if (entry->callback(entry->fd, entry->privdata) != 0) {
  250. list_del(&entry->list);
  251. free(entry);
  252. }
  253. }
  254. }
  255. }
  256. }