QNAP-TS419p system daemon
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.

332 lines
8.7 KiB

  1. /***************************************************************************
  2. * Copyright (C) 03/2010 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; version 2 of the License *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <errno.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(event_fd_list);
  29. static LIST_HEAD(event_timeout_list);
  30. struct event_fd {
  31. struct list_head list;
  32. unsigned int flags;
  33. int fd;
  34. int (*read_cb)(int fd, void *privdata);
  35. int (*write_cb)(int fd, void *privdata);
  36. void *read_priv;
  37. void *write_priv;
  38. };
  39. struct event_timeout {
  40. struct list_head list;
  41. unsigned int flags;
  42. struct timeval intervall;
  43. struct timeval nextrun;
  44. int (*callback)(int timerid, void *privdata);
  45. int timerid;
  46. void *privdata;
  47. };
  48. struct event_fd * event_add_fd(
  49. struct event_fd *entry,
  50. int fd,
  51. int type,
  52. int (*callback)(int fd, void *privdata),
  53. void *privdata)
  54. {
  55. /* check valid filediskriptor */
  56. if (fd < 0 || fd > FD_SETSIZE) {
  57. log_print(LOG_ERROR, "%s(): invalid fd", __FUNCTION__);
  58. return NULL;
  59. }
  60. /* check valid type (read/write) */
  61. if (!(type & FD_TYPES)) {
  62. log_print(LOG_ERROR, "%s(): invalid type", __FUNCTION__);
  63. return NULL;
  64. }
  65. /* create new entry */
  66. if (entry == NULL) {
  67. entry = malloc(sizeof(struct event_fd));
  68. if (entry == NULL) {
  69. log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__);
  70. return NULL;
  71. }
  72. memset(entry, 0, sizeof(struct event_fd));
  73. entry->flags |= EVENT_NEW;
  74. entry->fd = fd;
  75. /* put it on the list */
  76. list_add_tail(&entry->list, &event_fd_list);
  77. }
  78. if (type & FD_READ) {
  79. entry->flags = (callback != NULL) ? (entry->flags | FD_READ | EVENT_NEW) : (entry->flags & ~FD_READ);
  80. entry->read_cb = callback;
  81. entry->read_priv = privdata;
  82. } else if (type & FD_WRITE) {
  83. entry->flags = (callback != NULL) ? (entry->flags | FD_WRITE | EVENT_NEW) : (entry->flags & ~FD_WRITE);
  84. entry->write_cb = callback;
  85. entry->write_priv = privdata;
  86. }
  87. return entry;
  88. }
  89. int event_get_fd(struct event_fd *entry)
  90. {
  91. return (entry != NULL) ? entry->fd: -1;
  92. }
  93. void event_remove_fd(struct event_fd *entry)
  94. {
  95. /* mark the event as deleted -> remove in select() loop */
  96. entry->flags |= EVENT_DELETE;
  97. }
  98. static void add_timeval(struct timeval *ret, struct timeval *a, struct timeval *b)
  99. {
  100. ret->tv_usec = a->tv_usec + b->tv_usec;
  101. ret->tv_sec = a->tv_sec + b->tv_sec;
  102. if (ret->tv_usec >= 1000000) {
  103. ret->tv_usec -= 1000000;
  104. ret->tv_sec++;
  105. }
  106. }
  107. static void sub_timeval(struct timeval *ret, struct timeval *a, struct timeval *b)
  108. {
  109. ret->tv_usec = a->tv_usec - b->tv_usec;
  110. ret->tv_sec = a->tv_sec - b->tv_sec;
  111. if (ret->tv_usec < 0) {
  112. ret->tv_usec += 1000000;
  113. ret->tv_sec--;
  114. }
  115. }
  116. static int cmp_timeval(struct timeval *a, struct timeval *b)
  117. {
  118. if (a->tv_sec > b->tv_sec)
  119. return -1;
  120. if (a->tv_sec < b->tv_sec)
  121. return 1;
  122. if (a->tv_usec > b->tv_usec)
  123. return -1;
  124. if (a->tv_usec < b->tv_usec)
  125. return 1;
  126. return 0;
  127. }
  128. static void schedule_nextrun(struct event_timeout *entry, struct timeval *now)
  129. {
  130. add_timeval(&entry->nextrun, now, &entry->intervall);
  131. struct event_timeout *search;
  132. list_for_each_entry(search, &event_timeout_list, list) {
  133. if (search->nextrun.tv_sec > entry->nextrun.tv_sec) {
  134. list_add_tail(&entry->list, &search->list);
  135. return;
  136. } else if (search->nextrun.tv_sec == entry->nextrun.tv_sec &&
  137. search->nextrun.tv_usec > entry->nextrun.tv_usec) {
  138. list_add_tail(&entry->list, &search->list);
  139. return;
  140. }
  141. }
  142. list_add_tail(&entry->list, &event_timeout_list);
  143. }
  144. struct event_timeout * event_add_timeout(
  145. struct timeval *timeout,
  146. int (*callback)(int timerid, void *privdata),
  147. int timerid,
  148. void *privdata)
  149. {
  150. struct event_timeout *entry;
  151. entry = malloc(sizeof(struct event_timeout));
  152. if (entry == NULL) {
  153. log_print(LOG_ERROR, "%s(): out of memory", __FUNCTION__);
  154. return NULL;
  155. }
  156. entry->flags = 0;
  157. memcpy(&entry->intervall, timeout, sizeof(entry->intervall));
  158. entry->callback = callback;
  159. entry->timerid = timerid;
  160. entry->privdata = privdata;
  161. struct timeval now;
  162. gettimeofday(&now, NULL);
  163. schedule_nextrun(entry, &now);
  164. return entry;
  165. }
  166. struct event_timeout * event_add_timeout_ms(
  167. int timeout_ms,
  168. int (*callback)(int timerid, void *privdata),
  169. int timerid,
  170. void *privdata)
  171. {
  172. struct timeval tv;
  173. tv.tv_sec = timeout_ms / 1000;
  174. tv.tv_usec = (timeout_ms % 1000) * 1000;
  175. return event_add_timeout(&tv, callback, timerid, privdata);
  176. }
  177. void event_remove_timeout(struct event_timeout *entry)
  178. {
  179. /* mark the event as deleted -> remove in select() loop */
  180. entry->flags |= EVENT_DELETE;
  181. }
  182. int event_loop(int (*pre_select_cb)(int *maxfd, void *readfds, void *writefds, struct timeval *timeout, void *privdata),
  183. int (*post_select_cb)(int retval, void *readfds, void *writefds, void *privdata),
  184. void *privdata)
  185. {
  186. while (1) {
  187. /* default value if no application timeout is present */
  188. struct timeval timeout = {
  189. .tv_sec = -1,
  190. .tv_usec = -1,
  191. };
  192. if (!list_empty(&event_timeout_list)) {
  193. struct timeval now;
  194. gettimeofday(&now, NULL);
  195. struct event_timeout *entry, *tmp;
  196. list_for_each_entry_safe(entry, tmp, &event_timeout_list, list) {
  197. if (entry->flags & EVENT_DELETE) {
  198. list_del(&entry->list);
  199. free(entry);
  200. continue;
  201. }
  202. /* first timeout not elapsed, exit search (since list is sorted) */
  203. if (cmp_timeval(&entry->nextrun, &now) == -1)
  204. break;
  205. /* remove event from list */
  206. list_del(&entry->list);
  207. /* execute callback, when callback returns 0 -> schedule event again */
  208. if (entry->callback(entry->timerid, entry->privdata)) {
  209. free(entry);
  210. } else {
  211. schedule_nextrun(entry, &now);
  212. }
  213. }
  214. if (!list_empty(&event_timeout_list)) {
  215. entry = list_entry(event_timeout_list.next, typeof(*entry), list);
  216. /* calc select() timeout */
  217. sub_timeval(&timeout, &entry->nextrun, &now);
  218. }
  219. }
  220. struct event_fd *entry, *tmp;
  221. int maxfd = -1;
  222. fd_set readfds, writefds;
  223. FD_ZERO(&readfds);
  224. FD_ZERO(&writefds);
  225. list_for_each_entry_safe(entry, tmp, &event_fd_list, list) {
  226. entry->flags &= ~EVENT_NEW;
  227. if (entry->flags & EVENT_DELETE) {
  228. list_del(&entry->list);
  229. free(entry);
  230. continue;
  231. }
  232. if (entry->flags & FD_READ)
  233. FD_SET(entry->fd, &readfds);
  234. if (entry->flags & FD_WRITE)
  235. FD_SET(entry->fd, &writefds);
  236. maxfd = (entry->fd > maxfd) ? entry->fd : maxfd;
  237. }
  238. maxfd++;
  239. /* exit loop if callback returns true */
  240. if (pre_select_cb != NULL && pre_select_cb(&maxfd, (void *)&readfds, (void *)&writefds, &timeout, privdata) != 0)
  241. break;
  242. int retval;
  243. if (timeout.tv_sec == -1 && timeout.tv_usec == -1)
  244. retval = select(maxfd, &readfds, &writefds, NULL, NULL);
  245. else
  246. retval = select(maxfd, &readfds, &writefds, NULL, &timeout);
  247. /* exit loop if callback returns true */
  248. if (post_select_cb != NULL && post_select_cb(retval, (void *)&readfds, (void *)&writefds, privdata) != 0)
  249. break;
  250. if (retval < 0 && errno == EINTR) {
  251. errno = 0;
  252. continue;
  253. } else if (retval < 0) {
  254. log_print(LOG_ERROR, "%s(): select():", __FUNCTION__);
  255. continue;
  256. }
  257. /* timeout */
  258. if (retval == 0)
  259. continue;
  260. list_for_each_entry(entry, &event_fd_list, list) {
  261. if (((entry->flags & (FD_READ | EVENT_NEW)) == FD_READ) && FD_ISSET(entry->fd, &readfds))
  262. if (entry->read_cb(entry->fd, entry->read_priv) != 0)
  263. entry->flags |= EVENT_DELETE;
  264. if (((entry->flags & (FD_WRITE | EVENT_NEW)) == FD_WRITE) && FD_ISSET(entry->fd, &writefds))
  265. if (entry->write_cb(entry->fd, entry->write_priv) != 0)
  266. entry->flags |= EVENT_DELETE;
  267. }
  268. }
  269. return 0;
  270. }