scheduler.c 78 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2009-2017 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file util/scheduler.c
  18. * @brief schedule computations using continuation passing style
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "disk.h"
  24. // DEBUG
  25. #include <inttypes.h>
  26. #define LOG(kind, ...) GNUNET_log_from (kind, "util-scheduler", __VA_ARGS__)
  27. #define LOG_STRERROR(kind, syscall) GNUNET_log_from_strerror (kind, \
  28. "util-scheduler", \
  29. syscall)
  30. #if HAVE_EXECINFO_H
  31. #include "execinfo.h"
  32. /**
  33. * Use lsof to generate file descriptor reports on select error?
  34. * (turn off for stable releases).
  35. */
  36. #define USE_LSOF GNUNET_NO
  37. /**
  38. * Obtain trace information for all scheduler calls that schedule tasks.
  39. */
  40. #define EXECINFO GNUNET_NO
  41. /**
  42. * Check each file descriptor before adding
  43. */
  44. #define DEBUG_FDS GNUNET_NO
  45. /**
  46. * Depth of the traces collected via EXECINFO.
  47. */
  48. #define MAX_TRACE_DEPTH 50
  49. #endif
  50. /**
  51. * Should we figure out which tasks are delayed for a while
  52. * before they are run? (Consider using in combination with EXECINFO).
  53. */
  54. #define PROFILE_DELAYS GNUNET_NO
  55. /**
  56. * Task that were in the queue for longer than this are reported if
  57. * PROFILE_DELAYS is active.
  58. */
  59. #define DELAY_THRESHOLD GNUNET_TIME_UNIT_SECONDS
  60. /**
  61. * Argument to be passed from the driver to
  62. * #GNUNET_SCHEDULER_do_work(). Contains the
  63. * scheduler's internal state.
  64. */
  65. struct GNUNET_SCHEDULER_Handle
  66. {
  67. /**
  68. * Passed here to avoid constantly allocating/deallocating
  69. * this element, but generally we want to get rid of this.
  70. * @deprecated
  71. */
  72. struct GNUNET_NETWORK_FDSet *rs;
  73. /**
  74. * Passed here to avoid constantly allocating/deallocating
  75. * this element, but generally we want to get rid of this.
  76. * @deprecated
  77. */
  78. struct GNUNET_NETWORK_FDSet *ws;
  79. /**
  80. * context of the SIGINT handler
  81. */
  82. struct GNUNET_SIGNAL_Context *shc_int;
  83. /**
  84. * context of the SIGTERM handler
  85. */
  86. struct GNUNET_SIGNAL_Context *shc_term;
  87. #if (SIGTERM != GNUNET_TERM_SIG)
  88. /**
  89. * context of the TERM_SIG handler
  90. */
  91. struct GNUNET_SIGNAL_Context *shc_gterm;
  92. #endif
  93. /**
  94. * context of the SIGQUIT handler
  95. */
  96. struct GNUNET_SIGNAL_Context *shc_quit;
  97. /**
  98. * context of the SIGHUP handler
  99. */
  100. struct GNUNET_SIGNAL_Context *shc_hup;
  101. /**
  102. * context of hte SIGPIPE handler
  103. */
  104. struct GNUNET_SIGNAL_Context *shc_pipe;
  105. };
  106. /**
  107. * Entry in list of pending tasks.
  108. */
  109. struct GNUNET_SCHEDULER_Task
  110. {
  111. /**
  112. * This is a linked list.
  113. */
  114. struct GNUNET_SCHEDULER_Task *next;
  115. /**
  116. * This is a linked list.
  117. */
  118. struct GNUNET_SCHEDULER_Task *prev;
  119. /**
  120. * Function to run when ready.
  121. */
  122. GNUNET_SCHEDULER_TaskCallback callback;
  123. /**
  124. * Closure for the @e callback.
  125. */
  126. void *callback_cls;
  127. /**
  128. * Information about which FDs are ready for this task (and why).
  129. */
  130. struct GNUNET_SCHEDULER_FdInfo *fds;
  131. /**
  132. * Storage location used for @e fds if we want to avoid
  133. * a separate malloc() call in the common case that this
  134. * task is only about a single FD.
  135. */
  136. struct GNUNET_SCHEDULER_FdInfo fdx;
  137. /**
  138. * Size of the @e fds array.
  139. */
  140. unsigned int fds_len;
  141. /**
  142. * Do we own the network and file handles referenced by the FdInfo
  143. * structs in the fds array. This will only be GNUNET_YES if the
  144. * task was created by the #GNUNET_SCHEDULER_add_select function.
  145. */
  146. int own_handles;
  147. /**
  148. * Absolute timeout value for the task, or
  149. * #GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout".
  150. */
  151. struct GNUNET_TIME_Absolute timeout;
  152. #if PROFILE_DELAYS
  153. /**
  154. * When was the task scheduled?
  155. */
  156. struct GNUNET_TIME_Absolute start_time;
  157. #endif
  158. /**
  159. * Why is the task ready? Set after task is added to ready queue.
  160. * Initially set to zero. All reasons that have already been
  161. * satisfied (i.e. read or write ready) will be set over time.
  162. */
  163. enum GNUNET_SCHEDULER_Reason reason;
  164. /**
  165. * Task priority.
  166. */
  167. enum GNUNET_SCHEDULER_Priority priority;
  168. /**
  169. * Set if we only wait for reading from a single FD, otherwise -1.
  170. */
  171. int read_fd;
  172. /**
  173. * Set if we only wait for writing to a single FD, otherwise -1.
  174. */
  175. int write_fd;
  176. /**
  177. * Should the existence of this task in the queue be counted as
  178. * reason to not shutdown the scheduler?
  179. */
  180. int lifeness;
  181. /**
  182. * Is this task run on shutdown?
  183. */
  184. int on_shutdown;
  185. /**
  186. * Is this task in the ready list?
  187. */
  188. int in_ready_list;
  189. #if EXECINFO
  190. /**
  191. * Array of strings which make up a backtrace from the point when this
  192. * task was scheduled (essentially, who scheduled the task?)
  193. */
  194. char **backtrace_strings;
  195. /**
  196. * Size of the backtrace_strings array
  197. */
  198. int num_backtrace_strings;
  199. #endif
  200. /**
  201. * Asynchronous scope of the task that scheduled this scope,
  202. */
  203. struct GNUNET_AsyncScopeSave scope;
  204. };
  205. /**
  206. * A struct representing an event the select driver is waiting for
  207. */
  208. struct Scheduled
  209. {
  210. struct Scheduled *prev;
  211. struct Scheduled *next;
  212. /**
  213. * the task, the event is related to
  214. */
  215. struct GNUNET_SCHEDULER_Task *task;
  216. /**
  217. * information about the network socket / file descriptor where
  218. * the event is expected to occur
  219. */
  220. struct GNUNET_SCHEDULER_FdInfo *fdi;
  221. /**
  222. * the event types (multiple event types can be ORed) the select
  223. * driver is expected to wait for
  224. */
  225. enum GNUNET_SCHEDULER_EventType et;
  226. };
  227. /**
  228. * Driver context used by GNUNET_SCHEDULER_run
  229. */
  230. struct DriverContext
  231. {
  232. /**
  233. * the head of a DLL containing information about the events the
  234. * select driver is waiting for
  235. */
  236. struct Scheduled *scheduled_head;
  237. /**
  238. * the tail of a DLL containing information about the events the
  239. * select driver is waiting for
  240. */
  241. struct Scheduled *scheduled_tail;
  242. /**
  243. * the time when the select driver will wake up again (after
  244. * calling select)
  245. */
  246. struct GNUNET_TIME_Absolute timeout;
  247. };
  248. /**
  249. * The driver used for the event loop. Will be handed over to
  250. * the scheduler in #GNUNET_SCHEDULER_do_work(), persisted
  251. * there in this variable for later use in functions like
  252. * #GNUNET_SCHEDULER_add_select(), #add_without_sets() and
  253. * #GNUNET_SCHEDULER_cancel().
  254. */
  255. static const struct GNUNET_SCHEDULER_Driver *scheduler_driver;
  256. /**
  257. * Head of list of tasks waiting for an event.
  258. */
  259. static struct GNUNET_SCHEDULER_Task *pending_head;
  260. /**
  261. * Tail of list of tasks waiting for an event.
  262. */
  263. static struct GNUNET_SCHEDULER_Task *pending_tail;
  264. /**
  265. * Head of list of tasks waiting for shutdown.
  266. */
  267. static struct GNUNET_SCHEDULER_Task *shutdown_head;
  268. /**
  269. * Tail of list of tasks waiting for shutdown.
  270. */
  271. static struct GNUNET_SCHEDULER_Task *shutdown_tail;
  272. /**
  273. * List of tasks waiting ONLY for a timeout event.
  274. * Sorted by timeout (earliest first). Used so that
  275. * we do not traverse the list of these tasks when
  276. * building select sets (we just look at the head
  277. * to determine the respective timeout ONCE).
  278. */
  279. static struct GNUNET_SCHEDULER_Task *pending_timeout_head;
  280. /**
  281. * List of tasks waiting ONLY for a timeout event.
  282. * Sorted by timeout (earliest first). Used so that
  283. * we do not traverse the list of these tasks when
  284. * building select sets (we just look at the head
  285. * to determine the respective timeout ONCE).
  286. */
  287. static struct GNUNET_SCHEDULER_Task *pending_timeout_tail;
  288. /**
  289. * Last inserted task waiting ONLY for a timeout event.
  290. * Used to (heuristically) speed up insertion.
  291. */
  292. static struct GNUNET_SCHEDULER_Task *pending_timeout_last;
  293. /**
  294. * ID of the task that is running right now.
  295. */
  296. static struct GNUNET_SCHEDULER_Task *active_task;
  297. /**
  298. * Head of list of tasks ready to run right now, grouped by importance.
  299. */
  300. static struct
  301. GNUNET_SCHEDULER_Task *ready_head[GNUNET_SCHEDULER_PRIORITY_COUNT];
  302. /**
  303. * Tail of list of tasks ready to run right now, grouped by importance.
  304. */
  305. static struct
  306. GNUNET_SCHEDULER_Task *ready_tail[GNUNET_SCHEDULER_PRIORITY_COUNT];
  307. /**
  308. * Task for installing parent control handlers (it might happen that the
  309. * scheduler is shutdown before this task is executed, so
  310. * GNUNET_SCHEDULER_shutdown must cancel it in that case)
  311. */
  312. static struct GNUNET_SCHEDULER_Task *install_parent_control_task;
  313. /**
  314. * Task for reading from a pipe that signal handlers will use to initiate
  315. * shutdown
  316. */
  317. static struct GNUNET_SCHEDULER_Task *shutdown_pipe_task;
  318. /**
  319. * Number of tasks on the ready list.
  320. */
  321. static unsigned int ready_count;
  322. /**
  323. * Priority of the task running right now. Only
  324. * valid while a task is running.
  325. */
  326. static enum GNUNET_SCHEDULER_Priority current_priority;
  327. /**
  328. * Priority of the highest task added in the current select
  329. * iteration.
  330. */
  331. static enum GNUNET_SCHEDULER_Priority max_priority_added;
  332. /**
  333. * Value of the 'lifeness' flag for the current task.
  334. */
  335. static int current_lifeness;
  336. /**
  337. * Function to use as a select() in the scheduler.
  338. * If NULL, we use GNUNET_NETWORK_socket_select().
  339. */
  340. static GNUNET_SCHEDULER_select scheduler_select;
  341. /**
  342. * Task context of the current task.
  343. */
  344. static struct GNUNET_SCHEDULER_TaskContext tc;
  345. /**
  346. * Closure for #scheduler_select.
  347. */
  348. static void *scheduler_select_cls;
  349. /**
  350. * Sets the select function to use in the scheduler (scheduler_select).
  351. *
  352. * @param new_select new select function to use
  353. * @param new_select_cls closure for @a new_select
  354. * @return previously used select function, NULL for default
  355. */
  356. void
  357. GNUNET_SCHEDULER_set_select (GNUNET_SCHEDULER_select new_select,
  358. void *new_select_cls)
  359. {
  360. scheduler_select = new_select;
  361. scheduler_select_cls = new_select_cls;
  362. }
  363. /**
  364. * Check that the given priority is legal (and return it).
  365. *
  366. * @param p priority value to check
  367. * @return p on success, 0 on error
  368. */
  369. static enum GNUNET_SCHEDULER_Priority
  370. check_priority (enum GNUNET_SCHEDULER_Priority p)
  371. {
  372. if ((p >= 0) && (p < GNUNET_SCHEDULER_PRIORITY_COUNT))
  373. return p;
  374. GNUNET_assert (0);
  375. return 0; /* make compiler happy */
  376. }
  377. /**
  378. * chooses the nearest timeout from all pending tasks, to be used
  379. * to tell the driver the next wakeup time (using its set_wakeup
  380. * callback)
  381. */
  382. struct GNUNET_TIME_Absolute
  383. get_timeout ()
  384. {
  385. struct GNUNET_SCHEDULER_Task *pos;
  386. struct GNUNET_TIME_Absolute now;
  387. struct GNUNET_TIME_Absolute timeout;
  388. pos = pending_timeout_head;
  389. now = GNUNET_TIME_absolute_get ();
  390. timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
  391. if (NULL != pos)
  392. {
  393. if (0 != pos->reason)
  394. {
  395. return now;
  396. }
  397. else
  398. {
  399. timeout = pos->timeout;
  400. }
  401. }
  402. for (pos = pending_head; NULL != pos; pos = pos->next)
  403. {
  404. if (0 != pos->reason)
  405. {
  406. return now;
  407. }
  408. else if ((pos->timeout.abs_value_us !=
  409. GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) &&
  410. (timeout.abs_value_us > pos->timeout.abs_value_us))
  411. {
  412. timeout = pos->timeout;
  413. }
  414. }
  415. return timeout;
  416. }
  417. /**
  418. * Put a task that is ready for execution into the ready queue.
  419. *
  420. * @param task task ready for execution
  421. */
  422. static void
  423. queue_ready_task (struct GNUNET_SCHEDULER_Task *task)
  424. {
  425. enum GNUNET_SCHEDULER_Priority p = check_priority (task->priority);
  426. GNUNET_CONTAINER_DLL_insert (ready_head[p],
  427. ready_tail[p],
  428. task);
  429. task->in_ready_list = GNUNET_YES;
  430. ready_count++;
  431. }
  432. /**
  433. * Request the shutdown of a scheduler. Marks all tasks
  434. * awaiting shutdown as ready. Note that tasks
  435. * scheduled with #GNUNET_SCHEDULER_add_shutdown() AFTER this call
  436. * will be delayed until the next shutdown signal.
  437. */
  438. void
  439. GNUNET_SCHEDULER_shutdown ()
  440. {
  441. struct GNUNET_SCHEDULER_Task *pos;
  442. LOG (GNUNET_ERROR_TYPE_DEBUG,
  443. "GNUNET_SCHEDULER_shutdown\n");
  444. if (NULL != install_parent_control_task)
  445. {
  446. GNUNET_SCHEDULER_cancel (install_parent_control_task);
  447. install_parent_control_task = NULL;
  448. }
  449. if (NULL != shutdown_pipe_task)
  450. {
  451. GNUNET_SCHEDULER_cancel (shutdown_pipe_task);
  452. shutdown_pipe_task = NULL;
  453. }
  454. while (NULL != (pos = shutdown_head))
  455. {
  456. GNUNET_CONTAINER_DLL_remove (shutdown_head,
  457. shutdown_tail,
  458. pos);
  459. pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN;
  460. queue_ready_task (pos);
  461. }
  462. }
  463. /**
  464. * Output stack trace of task @a t.
  465. *
  466. * @param t task to dump stack trace of
  467. */
  468. static void
  469. dump_backtrace (struct GNUNET_SCHEDULER_Task *t)
  470. {
  471. #if EXECINFO
  472. for (unsigned int i = 0; i < t->num_backtrace_strings; i++)
  473. LOG (GNUNET_ERROR_TYPE_WARNING,
  474. "Task %p trace %u: %s\n",
  475. t,
  476. i,
  477. t->backtrace_strings[i]);
  478. #else
  479. (void) t;
  480. #endif
  481. }
  482. /**
  483. * Destroy a task (release associated resources)
  484. *
  485. * @param t task to destroy
  486. */
  487. static void
  488. destroy_task (struct GNUNET_SCHEDULER_Task *t)
  489. {
  490. unsigned int i;
  491. LOG (GNUNET_ERROR_TYPE_DEBUG,
  492. "destroying task %p\n",
  493. t);
  494. if (GNUNET_YES == t->own_handles)
  495. {
  496. for (i = 0; i != t->fds_len; ++i)
  497. {
  498. const struct GNUNET_NETWORK_Handle *fd = t->fds[i].fd;
  499. const struct GNUNET_DISK_FileHandle *fh = t->fds[i].fh;
  500. if (fd)
  501. {
  502. GNUNET_NETWORK_socket_free_memory_only_ ((struct
  503. GNUNET_NETWORK_Handle *) fd);
  504. }
  505. if (fh)
  506. {
  507. // FIXME: on WIN32 this is not enough! A function
  508. // GNUNET_DISK_file_free_memory_only would be nice
  509. GNUNET_free ((void *) fh);
  510. }
  511. }
  512. }
  513. if (t->fds_len > 1)
  514. {
  515. GNUNET_array_grow (t->fds, t->fds_len, 0);
  516. }
  517. #if EXECINFO
  518. GNUNET_free (t->backtrace_strings);
  519. #endif
  520. GNUNET_free (t);
  521. }
  522. /**
  523. * Pipe used to communicate shutdown via signal.
  524. */
  525. static struct GNUNET_DISK_PipeHandle *shutdown_pipe_handle;
  526. /**
  527. * Process ID of this process at the time we installed the various
  528. * signal handlers.
  529. */
  530. static pid_t my_pid;
  531. /**
  532. * Signal handler called for SIGPIPE.
  533. */
  534. static void
  535. sighandler_pipe ()
  536. {
  537. return;
  538. }
  539. ///**
  540. // * Wait for a short time.
  541. // * Sleeps for @a ms ms (as that should be long enough for virtually all
  542. // * modern systems to context switch and allow another process to do
  543. // * some 'real' work).
  544. // *
  545. // * @param ms how many ms to wait
  546. // */
  547. // static void
  548. // short_wait (unsigned int ms)
  549. // {
  550. // struct GNUNET_TIME_Relative timeout;
  551. //
  552. // timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, ms);
  553. // (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
  554. // }
  555. /**
  556. * Signal handler called for signals that should cause us to shutdown.
  557. */
  558. static void
  559. sighandler_shutdown ()
  560. {
  561. static char c;
  562. int old_errno = errno; /* backup errno */
  563. if (getpid () != my_pid)
  564. _exit (1); /* we have fork'ed since the signal handler was created,
  565. * ignore the signal, see https://gnunet.org/vfork discussion */
  566. GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
  567. (shutdown_pipe_handle, GNUNET_DISK_PIPE_END_WRITE),
  568. &c, sizeof(c));
  569. errno = old_errno;
  570. }
  571. static void
  572. shutdown_if_no_lifeness ()
  573. {
  574. struct GNUNET_SCHEDULER_Task *t;
  575. if (ready_count > 0)
  576. return;
  577. for (t = pending_head; NULL != t; t = t->next)
  578. if (GNUNET_YES == t->lifeness)
  579. return;
  580. for (t = shutdown_head; NULL != t; t = t->next)
  581. if (GNUNET_YES == t->lifeness)
  582. return;
  583. for (t = pending_timeout_head; NULL != t; t = t->next)
  584. if (GNUNET_YES == t->lifeness)
  585. return;
  586. /* No lifeness! */
  587. GNUNET_SCHEDULER_shutdown ();
  588. }
  589. static int
  590. select_loop (struct GNUNET_SCHEDULER_Handle *sh,
  591. struct DriverContext *context);
  592. /**
  593. * Initialize and run scheduler. This function will return when all
  594. * tasks have completed. On systems with signals, receiving a SIGTERM
  595. * (and other similar signals) will cause #GNUNET_SCHEDULER_shutdown()
  596. * to be run after the active task is complete. As a result, SIGTERM
  597. * causes all active tasks to be scheduled with reason
  598. * #GNUNET_SCHEDULER_REASON_SHUTDOWN. (However, tasks added
  599. * afterwards will execute normally!). Note that any particular signal
  600. * will only shut down one scheduler; applications should always only
  601. * create a single scheduler.
  602. *
  603. * @param task task to run immediately
  604. * @param task_cls closure of @a task
  605. */
  606. void
  607. GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_TaskCallback task,
  608. void *task_cls)
  609. {
  610. struct GNUNET_SCHEDULER_Handle *sh;
  611. struct GNUNET_SCHEDULER_Driver *driver;
  612. struct DriverContext context = { .scheduled_head = NULL,
  613. .scheduled_tail = NULL,
  614. .timeout = GNUNET_TIME_absolute_get () };
  615. driver = GNUNET_SCHEDULER_driver_select ();
  616. driver->cls = &context;
  617. sh = GNUNET_SCHEDULER_driver_init (driver);
  618. GNUNET_SCHEDULER_add_with_reason_and_priority (task,
  619. task_cls,
  620. GNUNET_SCHEDULER_REASON_STARTUP,
  621. GNUNET_SCHEDULER_PRIORITY_DEFAULT);
  622. select_loop (sh,
  623. &context);
  624. GNUNET_SCHEDULER_driver_done (sh);
  625. GNUNET_free (driver);
  626. }
  627. /**
  628. * Obtain the task context, giving the reason why the current task was
  629. * started.
  630. *
  631. * @return current tasks' scheduler context
  632. */
  633. const struct GNUNET_SCHEDULER_TaskContext *
  634. GNUNET_SCHEDULER_get_task_context ()
  635. {
  636. GNUNET_assert (NULL != active_task);
  637. return &tc;
  638. }
  639. /**
  640. * Get information about the current load of this scheduler. Use this
  641. * function to determine if an elective task should be added or simply
  642. * dropped (if the decision should be made based on the number of
  643. * tasks ready to run).
  644. *
  645. * @param p priority level to look at
  646. * @return number of tasks pending right now
  647. */
  648. unsigned int
  649. GNUNET_SCHEDULER_get_load (enum GNUNET_SCHEDULER_Priority p)
  650. {
  651. struct GNUNET_SCHEDULER_Task *pos;
  652. unsigned int ret;
  653. GNUNET_assert (NULL != active_task);
  654. if (p == GNUNET_SCHEDULER_PRIORITY_COUNT)
  655. return ready_count;
  656. if (p == GNUNET_SCHEDULER_PRIORITY_KEEP)
  657. p = current_priority;
  658. ret = 0;
  659. for (pos = ready_head[check_priority (p)]; NULL != pos; pos = pos->next)
  660. ret++;
  661. return ret;
  662. }
  663. void
  664. init_fd_info (struct GNUNET_SCHEDULER_Task *t,
  665. const struct GNUNET_NETWORK_Handle *const *read_nh,
  666. unsigned int read_nh_len,
  667. const struct GNUNET_NETWORK_Handle *const *write_nh,
  668. unsigned int write_nh_len,
  669. const struct GNUNET_DISK_FileHandle *const *read_fh,
  670. unsigned int read_fh_len,
  671. const struct GNUNET_DISK_FileHandle *const *write_fh,
  672. unsigned int write_fh_len)
  673. {
  674. // FIXME: if we have exactly two network handles / exactly two file handles
  675. // and they are equal, we can make one FdInfo with both
  676. // GNUNET_SCHEDULER_ET_IN and GNUNET_SCHEDULER_ET_OUT set.
  677. struct GNUNET_SCHEDULER_FdInfo *fdi;
  678. t->fds_len = read_nh_len + write_nh_len + read_fh_len + write_fh_len;
  679. if (1 == t->fds_len)
  680. {
  681. fdi = &t->fdx;
  682. t->fds = fdi;
  683. if (1 == read_nh_len)
  684. {
  685. GNUNET_assert (NULL != read_nh);
  686. GNUNET_assert (NULL != *read_nh);
  687. fdi->fd = *read_nh;
  688. fdi->et = GNUNET_SCHEDULER_ET_IN;
  689. fdi->sock = GNUNET_NETWORK_get_fd (*read_nh);
  690. t->read_fd = fdi->sock;
  691. t->write_fd = -1;
  692. }
  693. else if (1 == write_nh_len)
  694. {
  695. GNUNET_assert (NULL != write_nh);
  696. GNUNET_assert (NULL != *write_nh);
  697. fdi->fd = *write_nh;
  698. fdi->et = GNUNET_SCHEDULER_ET_OUT;
  699. fdi->sock = GNUNET_NETWORK_get_fd (*write_nh);
  700. t->read_fd = -1;
  701. t->write_fd = fdi->sock;
  702. }
  703. else if (1 == read_fh_len)
  704. {
  705. GNUNET_assert (NULL != read_fh);
  706. GNUNET_assert (NULL != *read_fh);
  707. fdi->fh = *read_fh;
  708. fdi->et = GNUNET_SCHEDULER_ET_IN;
  709. fdi->sock = (*read_fh)->fd; // FIXME: does not work under WIN32
  710. t->read_fd = fdi->sock;
  711. t->write_fd = -1;
  712. }
  713. else
  714. {
  715. GNUNET_assert (NULL != write_fh);
  716. GNUNET_assert (NULL != *write_fh);
  717. fdi->fh = *write_fh;
  718. fdi->et = GNUNET_SCHEDULER_ET_OUT;
  719. fdi->sock = (*write_fh)->fd; // FIXME: does not work under WIN32
  720. t->read_fd = -1;
  721. t->write_fd = fdi->sock;
  722. }
  723. }
  724. else
  725. {
  726. fdi = GNUNET_new_array (t->fds_len, struct GNUNET_SCHEDULER_FdInfo);
  727. t->fds = fdi;
  728. t->read_fd = -1;
  729. t->write_fd = -1;
  730. unsigned int i;
  731. for (i = 0; i != read_nh_len; ++i)
  732. {
  733. fdi->fd = read_nh[i];
  734. GNUNET_assert (NULL != fdi->fd);
  735. fdi->et = GNUNET_SCHEDULER_ET_IN;
  736. fdi->sock = GNUNET_NETWORK_get_fd (read_nh[i]);
  737. ++fdi;
  738. }
  739. for (i = 0; i != write_nh_len; ++i)
  740. {
  741. fdi->fd = write_nh[i];
  742. GNUNET_assert (NULL != fdi->fd);
  743. fdi->et = GNUNET_SCHEDULER_ET_OUT;
  744. fdi->sock = GNUNET_NETWORK_get_fd (write_nh[i]);
  745. ++fdi;
  746. }
  747. for (i = 0; i != read_fh_len; ++i)
  748. {
  749. fdi->fh = read_fh[i];
  750. GNUNET_assert (NULL != fdi->fh);
  751. fdi->et = GNUNET_SCHEDULER_ET_IN;
  752. fdi->sock = (read_fh[i])->fd; // FIXME: does not work under WIN32
  753. ++fdi;
  754. }
  755. for (i = 0; i != write_fh_len; ++i)
  756. {
  757. fdi->fh = write_fh[i];
  758. GNUNET_assert (NULL != fdi->fh);
  759. fdi->et = GNUNET_SCHEDULER_ET_OUT;
  760. fdi->sock = (write_fh[i])->fd; // FIXME: does not work under WIN32
  761. ++fdi;
  762. }
  763. }
  764. }
  765. /**
  766. * calls the given function @a func on each FdInfo related to @a t.
  767. * Optionally updates the event type field in each FdInfo after calling
  768. * @a func.
  769. *
  770. * @param t the task
  771. * @param driver_func the function to call with each FdInfo contained in
  772. * in @a t
  773. * @param if_not_ready only call @a driver_func on FdInfos that are not
  774. * ready
  775. * @param et the event type to be set in each FdInfo after calling
  776. * @a driver_func on it, or -1 if no updating not desired.
  777. */
  778. static void
  779. driver_add_multiple (struct GNUNET_SCHEDULER_Task *t)
  780. {
  781. struct GNUNET_SCHEDULER_FdInfo *fdi;
  782. int success = GNUNET_YES;
  783. for (unsigned int i = 0; i != t->fds_len; ++i)
  784. {
  785. fdi = &t->fds[i];
  786. success = scheduler_driver->add (scheduler_driver->cls,
  787. t,
  788. fdi) && success;
  789. fdi->et = GNUNET_SCHEDULER_ET_NONE;
  790. }
  791. if (GNUNET_YES != success)
  792. {
  793. LOG (GNUNET_ERROR_TYPE_ERROR,
  794. "driver could not add task\n");
  795. }
  796. }
  797. static void
  798. install_parent_control_handler (void *cls)
  799. {
  800. (void) cls;
  801. install_parent_control_task = NULL;
  802. GNUNET_OS_install_parent_control_handler (NULL);
  803. }
  804. static void
  805. shutdown_pipe_cb (void *cls)
  806. {
  807. char c;
  808. const struct GNUNET_DISK_FileHandle *pr;
  809. (void) cls;
  810. shutdown_pipe_task = NULL;
  811. pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle,
  812. GNUNET_DISK_PIPE_END_READ);
  813. GNUNET_assert (! GNUNET_DISK_handle_invalid (pr));
  814. /* consume the signal */
  815. GNUNET_DISK_file_read (pr, &c, sizeof(c));
  816. /* mark all active tasks as ready due to shutdown */
  817. GNUNET_SCHEDULER_shutdown ();
  818. shutdown_pipe_task =
  819. GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
  820. pr,
  821. &shutdown_pipe_cb,
  822. NULL);
  823. }
  824. /**
  825. * Cancel the task with the specified identifier.
  826. * The task must not yet have run. Only allowed to be called as long as the
  827. * scheduler is running, that is one of the following conditions is met:
  828. *
  829. * - #GNUNET_SCHEDULER_run has been called and has not returned yet
  830. * - #GNUNET_SCHEDULER_driver_init has been run and
  831. * #GNUNET_SCHEDULER_driver_done has not been called yet
  832. *
  833. * @param task id of the task to cancel
  834. * @return original closure of the task
  835. */
  836. void *
  837. GNUNET_SCHEDULER_cancel (struct GNUNET_SCHEDULER_Task *task)
  838. {
  839. enum GNUNET_SCHEDULER_Priority p;
  840. int is_fd_task;
  841. void *ret;
  842. LOG (GNUNET_ERROR_TYPE_DEBUG,
  843. "canceling task %p\n",
  844. task);
  845. /* scheduler must be running */
  846. GNUNET_assert (NULL != scheduler_driver);
  847. is_fd_task = (NULL != task->fds);
  848. if (is_fd_task)
  849. {
  850. int del_result = scheduler_driver->del (scheduler_driver->cls, task);
  851. if (GNUNET_OK != del_result)
  852. {
  853. LOG (GNUNET_ERROR_TYPE_ERROR,
  854. "driver could not delete task\n");
  855. GNUNET_assert (0);
  856. }
  857. }
  858. if (! task->in_ready_list)
  859. {
  860. if (is_fd_task)
  861. {
  862. GNUNET_CONTAINER_DLL_remove (pending_head,
  863. pending_tail,
  864. task);
  865. }
  866. else if (GNUNET_YES == task->on_shutdown)
  867. {
  868. GNUNET_CONTAINER_DLL_remove (shutdown_head,
  869. shutdown_tail,
  870. task);
  871. }
  872. else
  873. {
  874. GNUNET_CONTAINER_DLL_remove (pending_timeout_head,
  875. pending_timeout_tail,
  876. task);
  877. if (pending_timeout_last == task)
  878. pending_timeout_last = NULL;
  879. }
  880. }
  881. else
  882. {
  883. p = check_priority (task->priority);
  884. GNUNET_CONTAINER_DLL_remove (ready_head[p],
  885. ready_tail[p],
  886. task);
  887. ready_count--;
  888. }
  889. ret = task->callback_cls;
  890. destroy_task (task);
  891. return ret;
  892. }
  893. /**
  894. * Initialize backtrace data for task @a t
  895. *
  896. * @param t task to initialize
  897. */
  898. static void
  899. init_backtrace (struct GNUNET_SCHEDULER_Task *t)
  900. {
  901. #if EXECINFO
  902. void *backtrace_array[MAX_TRACE_DEPTH];
  903. t->num_backtrace_strings
  904. = backtrace (backtrace_array, MAX_TRACE_DEPTH);
  905. t->backtrace_strings =
  906. backtrace_symbols (backtrace_array,
  907. t->num_backtrace_strings);
  908. dump_backtrace (t);
  909. #else
  910. (void) t;
  911. #endif
  912. }
  913. /**
  914. * Continue the current execution with the given function. This is
  915. * similar to the other "add" functions except that there is no delay
  916. * and the reason code can be specified.
  917. *
  918. * @param task main function of the task
  919. * @param task_cls closure for @a task
  920. * @param reason reason for task invocation
  921. * @param priority priority to use for the task
  922. */
  923. void
  924. GNUNET_SCHEDULER_add_with_reason_and_priority (GNUNET_SCHEDULER_TaskCallback
  925. task,
  926. void *task_cls,
  927. enum GNUNET_SCHEDULER_Reason
  928. reason,
  929. enum GNUNET_SCHEDULER_Priority
  930. priority)
  931. {
  932. struct GNUNET_SCHEDULER_Task *t;
  933. /* scheduler must be running */
  934. GNUNET_assert (NULL != scheduler_driver);
  935. GNUNET_assert (NULL != task);
  936. t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
  937. t->read_fd = -1;
  938. t->write_fd = -1;
  939. t->callback = task;
  940. t->callback_cls = task_cls;
  941. #if PROFILE_DELAYS
  942. t->start_time = GNUNET_TIME_absolute_get ();
  943. #endif
  944. t->reason = reason;
  945. t->priority = check_priority (priority);
  946. t->lifeness = current_lifeness;
  947. LOG (GNUNET_ERROR_TYPE_DEBUG,
  948. "Adding continuation task %p\n",
  949. t);
  950. init_backtrace (t);
  951. queue_ready_task (t);
  952. }
  953. /**
  954. * Schedule a new task to be run at the specified time. The task
  955. * will be scheduled for execution at time @a at.
  956. *
  957. * @param at time when the operation should run
  958. * @param priority priority to use for the task
  959. * @param task main function of the task
  960. * @param task_cls closure of @a task
  961. * @return unique task identifier for the job
  962. * only valid until @a task is started!
  963. */
  964. struct GNUNET_SCHEDULER_Task *
  965. GNUNET_SCHEDULER_add_at_with_priority (struct GNUNET_TIME_Absolute at,
  966. enum GNUNET_SCHEDULER_Priority priority,
  967. GNUNET_SCHEDULER_TaskCallback task,
  968. void *task_cls)
  969. {
  970. struct GNUNET_SCHEDULER_Task *t;
  971. struct GNUNET_SCHEDULER_Task *pos;
  972. struct GNUNET_SCHEDULER_Task *prev;
  973. /* scheduler must be running */
  974. GNUNET_assert (NULL != scheduler_driver);
  975. GNUNET_assert (NULL != task);
  976. t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
  977. GNUNET_async_scope_get (&t->scope);
  978. t->callback = task;
  979. t->callback_cls = task_cls;
  980. t->read_fd = -1;
  981. t->write_fd = -1;
  982. #if PROFILE_DELAYS
  983. t->start_time = GNUNET_TIME_absolute_get ();
  984. #endif
  985. t->timeout = at;
  986. t->priority = check_priority (priority);
  987. t->lifeness = current_lifeness;
  988. /* try tail first (optimization in case we are
  989. * appending to a long list of tasks with timeouts) */
  990. if ((NULL == pending_timeout_head) ||
  991. (at.abs_value_us < pending_timeout_head->timeout.abs_value_us))
  992. {
  993. GNUNET_CONTAINER_DLL_insert (pending_timeout_head,
  994. pending_timeout_tail,
  995. t);
  996. }
  997. else
  998. {
  999. /* first move from heuristic start backwards to before start time */
  1000. prev = pending_timeout_last;
  1001. while ((NULL != prev) &&
  1002. (prev->timeout.abs_value_us > t->timeout.abs_value_us))
  1003. prev = prev->prev;
  1004. /* now, move from heuristic start (or head of list) forward to insertion point */
  1005. if (NULL == prev)
  1006. pos = pending_timeout_head;
  1007. else
  1008. pos = prev->next;
  1009. while ((NULL != pos) && (pos->timeout.abs_value_us <=
  1010. t->timeout.abs_value_us))
  1011. {
  1012. prev = pos;
  1013. pos = pos->next;
  1014. }
  1015. GNUNET_CONTAINER_DLL_insert_after (pending_timeout_head,
  1016. pending_timeout_tail,
  1017. prev,
  1018. t);
  1019. }
  1020. /* finally, update heuristic insertion point to last insertion... */
  1021. pending_timeout_last = t;
  1022. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1023. "Adding task %p\n",
  1024. t);
  1025. init_backtrace (t);
  1026. return t;
  1027. }
  1028. /**
  1029. * Schedule a new task to be run with a specified delay. The task
  1030. * will be scheduled for execution once the delay has expired.
  1031. *
  1032. * @param delay when should this operation time out?
  1033. * @param priority priority to use for the task
  1034. * @param task main function of the task
  1035. * @param task_cls closure of @a task
  1036. * @return unique task identifier for the job
  1037. * only valid until @a task is started!
  1038. */
  1039. struct GNUNET_SCHEDULER_Task *
  1040. GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay,
  1041. enum GNUNET_SCHEDULER_Priority
  1042. priority,
  1043. GNUNET_SCHEDULER_TaskCallback task,
  1044. void *task_cls)
  1045. {
  1046. return GNUNET_SCHEDULER_add_at_with_priority (
  1047. GNUNET_TIME_relative_to_absolute (delay),
  1048. priority,
  1049. task,
  1050. task_cls);
  1051. }
  1052. /**
  1053. * Schedule a new task to be run with a specified priority.
  1054. *
  1055. * @param prio how important is the new task?
  1056. * @param task main function of the task
  1057. * @param task_cls closure of @a task
  1058. * @return unique task identifier for the job
  1059. * only valid until @a task is started!
  1060. */
  1061. struct GNUNET_SCHEDULER_Task *
  1062. GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio,
  1063. GNUNET_SCHEDULER_TaskCallback task,
  1064. void *task_cls)
  1065. {
  1066. return GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_ZERO,
  1067. prio,
  1068. task,
  1069. task_cls);
  1070. }
  1071. /**
  1072. * Schedule a new task to be run at the specified time. The task
  1073. * will be scheduled for execution once specified time has been
  1074. * reached. It will be run with the DEFAULT priority.
  1075. *
  1076. * @param at time at which this operation should run
  1077. * @param task main function of the task
  1078. * @param task_cls closure of @a task
  1079. * @return unique task identifier for the job
  1080. * only valid until @a task is started!
  1081. */
  1082. struct GNUNET_SCHEDULER_Task *
  1083. GNUNET_SCHEDULER_add_at (struct GNUNET_TIME_Absolute at,
  1084. GNUNET_SCHEDULER_TaskCallback task,
  1085. void *task_cls)
  1086. {
  1087. return GNUNET_SCHEDULER_add_at_with_priority (at,
  1088. GNUNET_SCHEDULER_PRIORITY_DEFAULT,
  1089. task,
  1090. task_cls);
  1091. }
  1092. /**
  1093. * Schedule a new task to be run with a specified delay. The task
  1094. * will be scheduled for execution once the delay has expired. It
  1095. * will be run with the DEFAULT priority.
  1096. *
  1097. * @param delay when should this operation time out?
  1098. * @param task main function of the task
  1099. * @param task_cls closure of @a task
  1100. * @return unique task identifier for the job
  1101. * only valid until @a task is started!
  1102. */
  1103. struct GNUNET_SCHEDULER_Task *
  1104. GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay,
  1105. GNUNET_SCHEDULER_TaskCallback task,
  1106. void *task_cls)
  1107. {
  1108. return GNUNET_SCHEDULER_add_delayed_with_priority (delay,
  1109. GNUNET_SCHEDULER_PRIORITY_DEFAULT,
  1110. task,
  1111. task_cls);
  1112. }
  1113. /**
  1114. * Schedule a new task to be run as soon as possible. Note that this
  1115. * does not guarantee that this will be the next task that is being
  1116. * run, as other tasks with higher priority (or that are already ready
  1117. * to run) might get to run first. Just as with delays, clients must
  1118. * not rely on any particular order of execution between tasks
  1119. * scheduled concurrently.
  1120. *
  1121. * The task will be run with the DEFAULT priority.
  1122. *
  1123. * @param task main function of the task
  1124. * @param task_cls closure of @a task
  1125. * @return unique task identifier for the job
  1126. * only valid until @a task is started!
  1127. */
  1128. struct GNUNET_SCHEDULER_Task *
  1129. GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_TaskCallback task,
  1130. void *task_cls)
  1131. {
  1132. return GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_ZERO,
  1133. task,
  1134. task_cls);
  1135. }
  1136. /**
  1137. * Schedule a new task to be run on shutdown, that is when a CTRL-C
  1138. * signal is received, or when #GNUNET_SCHEDULER_shutdown() is being
  1139. * invoked.
  1140. *
  1141. * @param task main function of the task
  1142. * @param task_cls closure of @a task
  1143. * @return unique task identifier for the job
  1144. * only valid until @a task is started!
  1145. */
  1146. struct GNUNET_SCHEDULER_Task *
  1147. GNUNET_SCHEDULER_add_shutdown (GNUNET_SCHEDULER_TaskCallback task,
  1148. void *task_cls)
  1149. {
  1150. struct GNUNET_SCHEDULER_Task *t;
  1151. /* scheduler must be running */
  1152. GNUNET_assert (NULL != scheduler_driver);
  1153. GNUNET_assert (NULL != task);
  1154. t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
  1155. GNUNET_async_scope_get (&t->scope);
  1156. t->callback = task;
  1157. t->callback_cls = task_cls;
  1158. t->read_fd = -1;
  1159. t->write_fd = -1;
  1160. #if PROFILE_DELAYS
  1161. t->start_time = GNUNET_TIME_absolute_get ();
  1162. #endif
  1163. t->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
  1164. t->priority = GNUNET_SCHEDULER_PRIORITY_SHUTDOWN;
  1165. t->on_shutdown = GNUNET_YES;
  1166. t->lifeness = GNUNET_NO;
  1167. GNUNET_CONTAINER_DLL_insert (shutdown_head,
  1168. shutdown_tail,
  1169. t);
  1170. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1171. "Adding shutdown task %p\n",
  1172. t);
  1173. init_backtrace (t);
  1174. return t;
  1175. }
  1176. /**
  1177. * Schedule a new task to be run as soon as possible with the
  1178. * (transitive) ignore-shutdown flag either explicitly set or
  1179. * explicitly enabled. This task (and all tasks created from it,
  1180. * other than by another call to this function) will either count or
  1181. * not count for the "lifeness" of the process. This API is only
  1182. * useful in a few special cases.
  1183. *
  1184. * @param lifeness #GNUNET_YES if the task counts for lifeness, #GNUNET_NO if not.
  1185. * @param task main function of the task
  1186. * @param task_cls closure of @a task
  1187. * @return unique task identifier for the job
  1188. * only valid until @a task is started!
  1189. */
  1190. struct GNUNET_SCHEDULER_Task *
  1191. GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness,
  1192. GNUNET_SCHEDULER_TaskCallback task,
  1193. void *task_cls)
  1194. {
  1195. struct GNUNET_SCHEDULER_Task *ret;
  1196. ret = GNUNET_SCHEDULER_add_now (task, task_cls);
  1197. ret->lifeness = lifeness;
  1198. return ret;
  1199. }
  1200. #if DEBUG_FDS
  1201. /**
  1202. * check a raw file descriptor and abort if it is bad (for debugging purposes)
  1203. *
  1204. * @param t the task related to the file descriptor
  1205. * @param raw_fd the raw file descriptor to check
  1206. */
  1207. void
  1208. check_fd (struct GNUNET_SCHEDULER_Task *t, int raw_fd)
  1209. {
  1210. if (-1 != raw_fd)
  1211. {
  1212. int flags = fcntl (raw_fd, F_GETFD);
  1213. if ((flags == -1) && (errno == EBADF))
  1214. {
  1215. LOG (GNUNET_ERROR_TYPE_ERROR,
  1216. "Got invalid file descriptor %d!\n",
  1217. raw_fd);
  1218. init_backtrace (t);
  1219. GNUNET_assert (0);
  1220. }
  1221. }
  1222. }
  1223. #endif
  1224. /**
  1225. * Schedule a new task to be run with a specified delay or when any of
  1226. * the specified file descriptor sets is ready. The delay can be used
  1227. * as a timeout on the socket(s) being ready. The task will be
  1228. * scheduled for execution once either the delay has expired or any of
  1229. * the socket operations is ready. This is the most general
  1230. * function of the "add" family. Note that the "prerequisite_task"
  1231. * must be satisfied in addition to any of the other conditions. In
  1232. * other words, the task will be started when
  1233. * <code>
  1234. * (prerequisite-run)
  1235. * && (delay-ready
  1236. * || any-rs-ready
  1237. * || any-ws-ready)
  1238. * </code>
  1239. *
  1240. * @param delay how long should we wait?
  1241. * @param priority priority to use
  1242. * @param rfd file descriptor we want to read (can be -1)
  1243. * @param wfd file descriptors we want to write (can be -1)
  1244. * @param task main function of the task
  1245. * @param task_cls closure of @a task
  1246. * @return unique task identifier for the job
  1247. * only valid until @a task is started!
  1248. */
  1249. static struct GNUNET_SCHEDULER_Task *
  1250. add_without_sets (struct GNUNET_TIME_Relative delay,
  1251. enum GNUNET_SCHEDULER_Priority priority,
  1252. const struct GNUNET_NETWORK_Handle *read_nh,
  1253. const struct GNUNET_NETWORK_Handle *write_nh,
  1254. const struct GNUNET_DISK_FileHandle *read_fh,
  1255. const struct GNUNET_DISK_FileHandle *write_fh,
  1256. GNUNET_SCHEDULER_TaskCallback task,
  1257. void *task_cls)
  1258. {
  1259. struct GNUNET_SCHEDULER_Task *t;
  1260. /* scheduler must be running */
  1261. GNUNET_assert (NULL != scheduler_driver);
  1262. GNUNET_assert (NULL != task);
  1263. t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
  1264. GNUNET_async_scope_get (&t->scope);
  1265. init_fd_info (t,
  1266. &read_nh,
  1267. read_nh ? 1 : 0,
  1268. &write_nh,
  1269. write_nh ? 1 : 0,
  1270. &read_fh,
  1271. read_fh ? 1 : 0,
  1272. &write_fh,
  1273. write_fh ? 1 : 0);
  1274. t->callback = task;
  1275. t->callback_cls = task_cls;
  1276. #if DEBUG_FDS
  1277. check_fd (t, NULL != read_nh ? GNUNET_NETWORK_get_fd (read_nh) : -1);
  1278. check_fd (t, NULL != write_nh ? GNUNET_NETWORK_get_fd (write_nh) : -1);
  1279. check_fd (t, NULL != read_fh ? read_fh->fd : -1);
  1280. check_fd (t, NULL != write_fh ? write_fh->fd : -1);
  1281. #endif
  1282. #if PROFILE_DELAYS
  1283. t->start_time = GNUNET_TIME_absolute_get ();
  1284. #endif
  1285. t->timeout = GNUNET_TIME_relative_to_absolute (delay);
  1286. t->priority = check_priority ((priority == GNUNET_SCHEDULER_PRIORITY_KEEP) ?
  1287. current_priority : priority);
  1288. t->lifeness = current_lifeness;
  1289. GNUNET_CONTAINER_DLL_insert (pending_head,
  1290. pending_tail,
  1291. t);
  1292. driver_add_multiple (t);
  1293. max_priority_added = GNUNET_MAX (max_priority_added,
  1294. t->priority);
  1295. init_backtrace (t);
  1296. return t;
  1297. }
  1298. /**
  1299. * Schedule a new task to be run with a specified delay or when the
  1300. * specified file descriptor is ready for reading. The delay can be
  1301. * used as a timeout on the socket being ready. The task will be
  1302. * scheduled for execution once either the delay has expired or the
  1303. * socket operation is ready. It will be run with the DEFAULT priority.
  1304. * Only allowed to be called as long as the scheduler is running, that
  1305. * is one of the following conditions is met:
  1306. *
  1307. * - #GNUNET_SCHEDULER_run has been called and has not returned yet
  1308. * - #GNUNET_SCHEDULER_driver_init has been run and
  1309. * #GNUNET_SCHEDULER_driver_done has not been called yet
  1310. *
  1311. * @param delay when should this operation time out?
  1312. * @param rfd read file-descriptor
  1313. * @param task main function of the task
  1314. * @param task_cls closure of @a task
  1315. * @return unique task identifier for the job
  1316. * only valid until @a task is started!
  1317. */
  1318. struct GNUNET_SCHEDULER_Task *
  1319. GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay,
  1320. struct GNUNET_NETWORK_Handle *rfd,
  1321. GNUNET_SCHEDULER_TaskCallback task,
  1322. void *task_cls)
  1323. {
  1324. return GNUNET_SCHEDULER_add_read_net_with_priority (delay,
  1325. GNUNET_SCHEDULER_PRIORITY_DEFAULT,
  1326. rfd, task, task_cls);
  1327. }
  1328. /**
  1329. * Schedule a new task to be run with a specified priority and to be
  1330. * run after the specified delay or when the specified file descriptor
  1331. * is ready for reading. The delay can be used as a timeout on the
  1332. * socket being ready. The task will be scheduled for execution once
  1333. * either the delay has expired or the socket operation is ready. It
  1334. * will be run with the DEFAULT priority.
  1335. * Only allowed to be called as long as the scheduler is running, that
  1336. * is one of the following conditions is met:
  1337. *
  1338. * - #GNUNET_SCHEDULER_run has been called and has not returned yet
  1339. * - #GNUNET_SCHEDULER_driver_init has been run and
  1340. * #GNUNET_SCHEDULER_driver_done has not been called yet
  1341. *
  1342. * @param delay when should this operation time out?
  1343. * @param priority priority to use for the task
  1344. * @param rfd read file-descriptor
  1345. * @param task main function of the task
  1346. * @param task_cls closure of @a task
  1347. * @return unique task identifier for the job
  1348. * only valid until @a task is started!
  1349. */
  1350. struct GNUNET_SCHEDULER_Task *
  1351. GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay,
  1352. enum GNUNET_SCHEDULER_Priority
  1353. priority,
  1354. struct GNUNET_NETWORK_Handle *rfd,
  1355. GNUNET_SCHEDULER_TaskCallback task,
  1356. void *task_cls)
  1357. {
  1358. return GNUNET_SCHEDULER_add_net_with_priority (delay, priority,
  1359. rfd,
  1360. GNUNET_YES,
  1361. GNUNET_NO,
  1362. task, task_cls);
  1363. }
  1364. /**
  1365. * Schedule a new task to be run with a specified delay or when the
  1366. * specified file descriptor is ready for writing. The delay can be
  1367. * used as a timeout on the socket being ready. The task will be
  1368. * scheduled for execution once either the delay has expired or the
  1369. * socket operation is ready. It will be run with the priority of
  1370. * the calling task.
  1371. * Only allowed to be called as long as the scheduler is running, that
  1372. * is one of the following conditions is met:
  1373. *
  1374. * - #GNUNET_SCHEDULER_run has been called and has not returned yet
  1375. * - #GNUNET_SCHEDULER_driver_init has been run and
  1376. * #GNUNET_SCHEDULER_driver_done has not been called yet
  1377. *
  1378. * @param delay when should this operation time out?
  1379. * @param wfd write file-descriptor
  1380. * @param task main function of the task
  1381. * @param task_cls closure of @a task
  1382. * @return unique task identifier for the job
  1383. * only valid until @a task is started!
  1384. */
  1385. struct GNUNET_SCHEDULER_Task *
  1386. GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay,
  1387. struct GNUNET_NETWORK_Handle *wfd,
  1388. GNUNET_SCHEDULER_TaskCallback task,
  1389. void *task_cls)
  1390. {
  1391. return GNUNET_SCHEDULER_add_net_with_priority (delay,
  1392. GNUNET_SCHEDULER_PRIORITY_DEFAULT,
  1393. wfd,
  1394. GNUNET_NO, GNUNET_YES,
  1395. task, task_cls);
  1396. }
  1397. /**
  1398. * Schedule a new task to be run with a specified delay or when the
  1399. * specified file descriptor is ready. The delay can be
  1400. * used as a timeout on the socket being ready. The task will be
  1401. * scheduled for execution once either the delay has expired or the
  1402. * socket operation is ready.
  1403. * Only allowed to be called as long as the scheduler is running, that
  1404. * is one of the following conditions is met:
  1405. *
  1406. * - #GNUNET_SCHEDULER_run has been called and has not returned yet
  1407. * - #GNUNET_SCHEDULER_driver_init has been run and
  1408. * #GNUNET_SCHEDULER_driver_done has not been called yet
  1409. *
  1410. * @param delay when should this operation time out?
  1411. * @param priority priority of the task
  1412. * @param fd file-descriptor
  1413. * @param on_read whether to poll the file-descriptor for readability
  1414. * @param on_write whether to poll the file-descriptor for writability
  1415. * @param task main function of the task
  1416. * @param task_cls closure of task
  1417. * @return unique task identifier for the job
  1418. * only valid until "task" is started!
  1419. */
  1420. struct GNUNET_SCHEDULER_Task *
  1421. GNUNET_SCHEDULER_add_net_with_priority (struct GNUNET_TIME_Relative delay,
  1422. enum GNUNET_SCHEDULER_Priority priority,
  1423. struct GNUNET_NETWORK_Handle *fd,
  1424. int on_read,
  1425. int on_write,
  1426. GNUNET_SCHEDULER_TaskCallback task,
  1427. void *task_cls)
  1428. {
  1429. /* scheduler must be running */
  1430. GNUNET_assert (NULL != scheduler_driver);
  1431. GNUNET_assert (on_read || on_write);
  1432. GNUNET_assert (GNUNET_NETWORK_get_fd (fd) >= 0);
  1433. return add_without_sets (delay, priority,
  1434. on_read ? fd : NULL,
  1435. on_write ? fd : NULL,
  1436. NULL,
  1437. NULL,
  1438. task, task_cls);
  1439. }
  1440. /**
  1441. * Schedule a new task to be run with a specified delay or when the
  1442. * specified file descriptor is ready for reading. The delay can be
  1443. * used as a timeout on the socket being ready. The task will be
  1444. * scheduled for execution once either the delay has expired or the
  1445. * socket operation is ready. It will be run with the DEFAULT priority.
  1446. * Only allowed to be called as long as the scheduler is running, that
  1447. * is one of the following conditions is met:
  1448. *
  1449. * - #GNUNET_SCHEDULER_run has been called and has not returned yet
  1450. * - #GNUNET_SCHEDULER_driver_init has been run and
  1451. * #GNUNET_SCHEDULER_driver_done has not been called yet
  1452. *
  1453. * @param delay when should this operation time out?
  1454. * @param rfd read file-descriptor
  1455. * @param task main function of the task
  1456. * @param task_cls closure of @a task
  1457. * @return unique task identifier for the job
  1458. * only valid until @a task is started!
  1459. */
  1460. struct GNUNET_SCHEDULER_Task *
  1461. GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay,
  1462. const struct GNUNET_DISK_FileHandle *rfd,
  1463. GNUNET_SCHEDULER_TaskCallback task,
  1464. void *task_cls)
  1465. {
  1466. return GNUNET_SCHEDULER_add_file_with_priority (
  1467. delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
  1468. rfd, GNUNET_YES, GNUNET_NO,
  1469. task, task_cls);
  1470. }
  1471. /**
  1472. * Schedule a new task to be run with a specified delay or when the
  1473. * specified file descriptor is ready for writing. The delay can be
  1474. * used as a timeout on the socket being ready. The task will be
  1475. * scheduled for execution once either the delay has expired or the
  1476. * socket operation is ready. It will be run with the DEFAULT priority.
  1477. * Only allowed to be called as long as the scheduler is running, that
  1478. * is one of the following conditions is met:
  1479. *
  1480. * - #GNUNET_SCHEDULER_run has been called and has not returned yet
  1481. * - #GNUNET_SCHEDULER_driver_init has been run and
  1482. * #GNUNET_SCHEDULER_driver_done has not been called yet
  1483. *
  1484. * @param delay when should this operation time out?
  1485. * @param wfd write file-descriptor
  1486. * @param task main function of the task
  1487. * @param task_cls closure of @a task
  1488. * @return unique task identifier for the job
  1489. * only valid until @a task is started!
  1490. */
  1491. struct GNUNET_SCHEDULER_Task *
  1492. GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
  1493. const struct GNUNET_DISK_FileHandle *wfd,
  1494. GNUNET_SCHEDULER_TaskCallback task,
  1495. void *task_cls)
  1496. {
  1497. return GNUNET_SCHEDULER_add_file_with_priority (
  1498. delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
  1499. wfd, GNUNET_NO, GNUNET_YES,
  1500. task, task_cls);
  1501. }
  1502. /**
  1503. * Schedule a new task to be run with a specified delay or when the
  1504. * specified file descriptor is ready. The delay can be
  1505. * used as a timeout on the socket being ready. The task will be
  1506. * scheduled for execution once either the delay has expired or the
  1507. * socket operation is ready.
  1508. * Only allowed to be called as long as the scheduler is running, that
  1509. * is one of the following conditions is met:
  1510. *
  1511. * - #GNUNET_SCHEDULER_run has been called and has not returned yet
  1512. * - #GNUNET_SCHEDULER_driver_init has been run and
  1513. * #GNUNET_SCHEDULER_driver_done has not been called yet
  1514. *
  1515. * @param delay when should this operation time out?
  1516. * @param priority priority of the task
  1517. * @param fd file-descriptor
  1518. * @param on_read whether to poll the file-descriptor for readability
  1519. * @param on_write whether to poll the file-descriptor for writability
  1520. * @param task main function of the task
  1521. * @param task_cls closure of @a task
  1522. * @return unique task identifier for the job
  1523. * only valid until @a task is started!
  1524. */
  1525. struct GNUNET_SCHEDULER_Task *
  1526. GNUNET_SCHEDULER_add_file_with_priority (struct GNUNET_TIME_Relative delay,
  1527. enum GNUNET_SCHEDULER_Priority
  1528. priority,
  1529. const struct
  1530. GNUNET_DISK_FileHandle *fd,
  1531. int on_read, int on_write,
  1532. GNUNET_SCHEDULER_TaskCallback task,
  1533. void *task_cls)
  1534. {
  1535. /* scheduler must be running */
  1536. GNUNET_assert (NULL != scheduler_driver);
  1537. GNUNET_assert (on_read || on_write);
  1538. GNUNET_assert (fd->fd >= 0);
  1539. return add_without_sets (delay, priority,
  1540. NULL,
  1541. NULL,
  1542. on_read ? fd : NULL,
  1543. on_write ? fd : NULL,
  1544. task, task_cls);
  1545. }
  1546. void
  1547. extract_handles (const struct GNUNET_NETWORK_FDSet *fdset,
  1548. const struct GNUNET_NETWORK_Handle ***ntarget,
  1549. unsigned int *extracted_nhandles,
  1550. const struct GNUNET_DISK_FileHandle ***ftarget,
  1551. unsigned int *extracted_fhandles)
  1552. {
  1553. // FIXME: this implementation only works for unix, for WIN32 the file handles
  1554. // in fdset must be handled separately
  1555. const struct GNUNET_NETWORK_Handle **nhandles;
  1556. const struct GNUNET_DISK_FileHandle **fhandles;
  1557. unsigned int nhandles_len;
  1558. unsigned int fhandles_len;
  1559. nhandles = NULL;
  1560. fhandles = NULL;
  1561. nhandles_len = 0;
  1562. fhandles_len = 0;
  1563. for (int sock = 0; sock != fdset->nsds; ++sock)
  1564. {
  1565. if (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (fdset, sock))
  1566. {
  1567. struct GNUNET_NETWORK_Handle *nhandle;
  1568. struct GNUNET_DISK_FileHandle *fhandle;
  1569. nhandle = GNUNET_NETWORK_socket_box_native (sock);
  1570. if (NULL != nhandle)
  1571. {
  1572. GNUNET_array_append (nhandles, nhandles_len, nhandle);
  1573. }
  1574. else
  1575. {
  1576. fhandle = GNUNET_DISK_get_handle_from_int_fd (sock);
  1577. if (NULL != fhandle)
  1578. {
  1579. GNUNET_array_append (fhandles, fhandles_len, fhandle);
  1580. }
  1581. else
  1582. {
  1583. GNUNET_assert (0);
  1584. }
  1585. }
  1586. }
  1587. }
  1588. *ntarget = nhandles_len > 0 ? nhandles : NULL;
  1589. *ftarget = fhandles_len > 0 ? fhandles : NULL;
  1590. *extracted_nhandles = nhandles_len;
  1591. *extracted_fhandles = fhandles_len;
  1592. }
  1593. /**
  1594. * Schedule a new task to be run with a specified delay or when any of
  1595. * the specified file descriptor sets is ready. The delay can be used
  1596. * as a timeout on the socket(s) being ready. The task will be
  1597. * scheduled for execution once either the delay has expired or any of
  1598. * the socket operations is ready. This is the most general
  1599. * function of the "add" family. Note that the "prerequisite_task"
  1600. * must be satisfied in addition to any of the other conditions. In
  1601. * other words, the task will be started when
  1602. * <code>
  1603. * (prerequisite-run)
  1604. * && (delay-ready
  1605. * || any-rs-ready
  1606. * || any-ws-ready) )
  1607. * </code>
  1608. * Only allowed to be called as long as the scheduler is running, that
  1609. * is one of the following conditions is met:
  1610. *
  1611. * - #GNUNET_SCHEDULER_run has been called and has not returned yet
  1612. * - #GNUNET_SCHEDULER_driver_init has been run and
  1613. * #GNUNET_SCHEDULER_driver_done has not been called yet
  1614. *
  1615. * @param prio how important is this task?
  1616. * @param delay how long should we wait?
  1617. * @param rs set of file descriptors we want to read (can be NULL)
  1618. * @param ws set of file descriptors we want to write (can be NULL)
  1619. * @param task main function of the task
  1620. * @param task_cls closure of @a task
  1621. * @return unique task identifier for the job
  1622. * only valid until @a task is started!
  1623. */
  1624. struct GNUNET_SCHEDULER_Task *
  1625. GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio,
  1626. struct GNUNET_TIME_Relative delay,
  1627. const struct GNUNET_NETWORK_FDSet *rs,
  1628. const struct GNUNET_NETWORK_FDSet *ws,
  1629. GNUNET_SCHEDULER_TaskCallback task,
  1630. void *task_cls)
  1631. {
  1632. struct GNUNET_SCHEDULER_Task *t;
  1633. const struct GNUNET_NETWORK_Handle **read_nhandles = NULL;
  1634. const struct GNUNET_NETWORK_Handle **write_nhandles = NULL;
  1635. const struct GNUNET_DISK_FileHandle **read_fhandles = NULL;
  1636. const struct GNUNET_DISK_FileHandle **write_fhandles = NULL;
  1637. unsigned int read_nhandles_len = 0;
  1638. unsigned int write_nhandles_len = 0;
  1639. unsigned int read_fhandles_len = 0;
  1640. unsigned int write_fhandles_len = 0;
  1641. /* scheduler must be running */
  1642. GNUNET_assert (NULL != scheduler_driver);
  1643. GNUNET_assert (NULL != task);
  1644. int no_rs = (NULL == rs);
  1645. int no_ws = (NULL == ws);
  1646. int empty_rs = (NULL != rs) && (0 == rs->nsds);
  1647. int empty_ws = (NULL != ws) && (0 == ws->nsds);
  1648. int no_fds = (no_rs && no_ws) ||
  1649. (empty_rs && empty_ws) ||
  1650. (no_rs && empty_ws) ||
  1651. (no_ws && empty_rs);
  1652. if (! no_fds)
  1653. {
  1654. if (NULL != rs)
  1655. {
  1656. extract_handles (rs,
  1657. &read_nhandles,
  1658. &read_nhandles_len,
  1659. &read_fhandles,
  1660. &read_fhandles_len);
  1661. }
  1662. if (NULL != ws)
  1663. {
  1664. extract_handles (ws,
  1665. &write_nhandles,
  1666. &write_nhandles_len,
  1667. &write_fhandles,
  1668. &write_fhandles_len);
  1669. }
  1670. }
  1671. /**
  1672. * here we consider the case that a GNUNET_NETWORK_FDSet might be empty
  1673. * although its maximum FD number (nsds) is greater than 0. We handle
  1674. * this case gracefully because some libraries such as libmicrohttpd
  1675. * only provide a hint what the maximum FD number in an FD set might be
  1676. * and not the exact FD number (see e.g. gnunet-rest-service.c)
  1677. */int no_fds_extracted = (0 == read_nhandles_len) &&
  1678. (0 == read_fhandles_len) &&
  1679. (0 == write_nhandles_len) &&
  1680. (0 == write_fhandles_len);
  1681. if (no_fds || no_fds_extracted)
  1682. return GNUNET_SCHEDULER_add_delayed_with_priority (delay,
  1683. prio,
  1684. task,
  1685. task_cls);
  1686. t = GNUNET_new (struct GNUNET_SCHEDULER_Task);
  1687. GNUNET_async_scope_get (&t->scope);
  1688. init_fd_info (t,
  1689. read_nhandles,
  1690. read_nhandles_len,
  1691. write_nhandles,
  1692. write_nhandles_len,
  1693. read_fhandles,
  1694. read_fhandles_len,
  1695. write_fhandles,
  1696. write_fhandles_len);
  1697. t->callback = task;
  1698. t->callback_cls = task_cls;
  1699. t->own_handles = GNUNET_YES;
  1700. /* free the arrays of pointers to network / file handles, the actual
  1701. * handles will be freed in destroy_task */
  1702. GNUNET_array_grow (read_nhandles, read_nhandles_len, 0);
  1703. GNUNET_array_grow (write_nhandles, write_nhandles_len, 0);
  1704. GNUNET_array_grow (read_fhandles, read_fhandles_len, 0);
  1705. GNUNET_array_grow (write_fhandles, write_fhandles_len, 0);
  1706. #if PROFILE_DELAYS
  1707. t->start_time = GNUNET_TIME_absolute_get ();
  1708. #endif
  1709. t->timeout = GNUNET_TIME_relative_to_absolute (delay);
  1710. t->priority =
  1711. check_priority ((prio ==
  1712. GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority :
  1713. prio);
  1714. t->lifeness = current_lifeness;
  1715. GNUNET_CONTAINER_DLL_insert (pending_head,
  1716. pending_tail,
  1717. t);
  1718. driver_add_multiple (t);
  1719. max_priority_added = GNUNET_MAX (max_priority_added,
  1720. t->priority);
  1721. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1722. "Adding task %p\n",
  1723. t);
  1724. init_backtrace (t);
  1725. return t;
  1726. }
  1727. /**
  1728. * Function used by event-loop implementations to signal the scheduler
  1729. * that a particular @a task is ready due to an event specified in the
  1730. * et field of @a fdi.
  1731. *
  1732. * This function will then queue the task to notify the application
  1733. * that the task is ready (with the respective priority).
  1734. *
  1735. * @param task the task that is ready
  1736. * @param fdi information about the related FD
  1737. */
  1738. void
  1739. GNUNET_SCHEDULER_task_ready (struct GNUNET_SCHEDULER_Task *task,
  1740. struct GNUNET_SCHEDULER_FdInfo *fdi)
  1741. {
  1742. enum GNUNET_SCHEDULER_Reason reason;
  1743. reason = task->reason;
  1744. if ((0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
  1745. (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et)))
  1746. reason |= GNUNET_SCHEDULER_REASON_READ_READY;
  1747. if ((0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) &&
  1748. (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et)))
  1749. reason |= GNUNET_SCHEDULER_REASON_WRITE_READY;
  1750. reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE;
  1751. task->reason = reason;
  1752. if (GNUNET_NO == task->in_ready_list)
  1753. {
  1754. GNUNET_CONTAINER_DLL_remove (pending_head,
  1755. pending_tail,
  1756. task);
  1757. queue_ready_task (task);
  1758. }
  1759. }
  1760. /**
  1761. * Function called by external event loop implementations to tell the
  1762. * scheduler to run some of the tasks that are ready. Must be called
  1763. * only after #GNUNET_SCHEDULER_driver_init has been called and before
  1764. * #GNUNET_SCHEDULER_driver_done is called.
  1765. * This function may return even though there are tasks left to run
  1766. * just to give other tasks a chance as well. If we return #GNUNET_YES,
  1767. * the event loop implementation should call this function again as
  1768. * soon as possible, while if we return #GNUNET_NO it must block until
  1769. * either the operating system has more work (the scheduler has no more
  1770. * work to do right now) or the timeout set by the scheduler (using the
  1771. * set_wakeup callback) is reached.
  1772. *
  1773. * @param sh scheduler handle that was returned by
  1774. * #GNUNET_SCHEDULER_driver_init
  1775. * @return #GNUNET_YES if there are more tasks that are ready,
  1776. * and thus we would like to run more (yield to avoid
  1777. * blocking other activities for too long) #GNUNET_NO
  1778. * if we are done running tasks (yield to block)
  1779. */
  1780. int
  1781. GNUNET_SCHEDULER_do_work (struct GNUNET_SCHEDULER_Handle *sh)
  1782. {
  1783. enum GNUNET_SCHEDULER_Priority p;
  1784. struct GNUNET_SCHEDULER_Task *pos;
  1785. struct GNUNET_TIME_Absolute now;
  1786. /* check for tasks that reached the timeout! */
  1787. now = GNUNET_TIME_absolute_get ();
  1788. pos = pending_timeout_head;
  1789. while (NULL != pos)
  1790. {
  1791. struct GNUNET_SCHEDULER_Task *next = pos->next;
  1792. if (now.abs_value_us >= pos->timeout.abs_value_us)
  1793. pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
  1794. if (0 == pos->reason)
  1795. break;
  1796. GNUNET_CONTAINER_DLL_remove (pending_timeout_head,
  1797. pending_timeout_tail,
  1798. pos);
  1799. if (pending_timeout_last == pos)
  1800. pending_timeout_last = NULL;
  1801. queue_ready_task (pos);
  1802. pos = next;
  1803. }
  1804. pos = pending_head;
  1805. while (NULL != pos)
  1806. {
  1807. struct GNUNET_SCHEDULER_Task *next = pos->next;
  1808. if (now.abs_value_us >= pos->timeout.abs_value_us)
  1809. {
  1810. pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT;
  1811. GNUNET_CONTAINER_DLL_remove (pending_head,
  1812. pending_tail,
  1813. pos);
  1814. queue_ready_task (pos);
  1815. }
  1816. pos = next;
  1817. }
  1818. if (0 == ready_count)
  1819. {
  1820. struct GNUNET_TIME_Absolute timeout = get_timeout ();
  1821. if (timeout.abs_value_us > now.abs_value_us)
  1822. {
  1823. /**
  1824. * The event loop called this function before the current timeout was
  1825. * reached (and no FD tasks are ready). This is acceptable if
  1826. *
  1827. * - the system time was changed while the driver was waiting for
  1828. * the timeout
  1829. * - an external event loop called GNUnet API functions outside of
  1830. * the callbacks called in GNUNET_SCHEDULER_do_work and thus
  1831. * wasn't notified about the new timeout
  1832. *
  1833. * It might also mean we are busy-waiting because of a programming
  1834. * error in the external event loop.
  1835. */LOG (GNUNET_ERROR_TYPE_DEBUG,
  1836. "GNUNET_SCHEDULER_do_work did not find any ready "
  1837. "tasks and timeout has not been reached yet.\n");
  1838. }
  1839. else
  1840. {
  1841. /**
  1842. * the current timeout was reached but no ready tasks were found,
  1843. * internal scheduler error!
  1844. */
  1845. GNUNET_assert (0);
  1846. }
  1847. }
  1848. else
  1849. {
  1850. /* find out which task priority level we are going to
  1851. process this time */
  1852. max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP;
  1853. GNUNET_assert (NULL == ready_head[GNUNET_SCHEDULER_PRIORITY_KEEP]);
  1854. /* yes, p>0 is correct, 0 is "KEEP" which should
  1855. * always be an empty queue (see assertion)! */
  1856. for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--)
  1857. {
  1858. pos = ready_head[p];
  1859. if (NULL != pos)
  1860. break;
  1861. }
  1862. GNUNET_assert (NULL != pos); /* ready_count wrong? */
  1863. /* process all tasks at this priority level, then yield */
  1864. while (NULL != (pos = ready_head[p]))
  1865. {
  1866. GNUNET_CONTAINER_DLL_remove (ready_head[p],
  1867. ready_tail[p],
  1868. pos);
  1869. ready_count--;
  1870. current_priority = pos->priority;
  1871. current_lifeness = pos->lifeness;
  1872. active_task = pos;
  1873. #if PROFILE_DELAYS
  1874. if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value_us >
  1875. DELAY_THRESHOLD.rel_value_us)
  1876. {
  1877. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1878. "Task %p took %s to be scheduled\n",
  1879. pos,
  1880. GNUNET_STRINGS_relative_time_to_string (
  1881. GNUNET_TIME_absolute_get_duration (pos->start_time),
  1882. GNUNET_YES));
  1883. }
  1884. #endif
  1885. tc.reason = pos->reason;
  1886. GNUNET_NETWORK_fdset_zero (sh->rs);
  1887. GNUNET_NETWORK_fdset_zero (sh->ws);
  1888. // FIXME: do we have to remove FdInfos from fds if they are not ready?
  1889. tc.fds_len = pos->fds_len;
  1890. tc.fds = pos->fds;
  1891. for (unsigned int i = 0; i != pos->fds_len; ++i)
  1892. {
  1893. struct GNUNET_SCHEDULER_FdInfo *fdi = &pos->fds[i];
  1894. if (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et))
  1895. {
  1896. GNUNET_NETWORK_fdset_set_native (sh->rs,
  1897. fdi->sock);
  1898. }
  1899. if (0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et))
  1900. {
  1901. GNUNET_NETWORK_fdset_set_native (sh->ws,
  1902. fdi->sock);
  1903. }
  1904. }
  1905. tc.read_ready = sh->rs;
  1906. tc.write_ready = sh->ws;
  1907. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1908. "Running task %p\n",
  1909. pos);
  1910. GNUNET_assert (NULL != pos->callback);
  1911. {
  1912. struct GNUNET_AsyncScopeSave old_scope;
  1913. if (pos->scope.have_scope)
  1914. GNUNET_async_scope_enter (&pos->scope.scope_id, &old_scope);
  1915. else
  1916. GNUNET_async_scope_get (&old_scope);
  1917. pos->callback (pos->callback_cls);
  1918. GNUNET_async_scope_restore (&old_scope);
  1919. }
  1920. if (NULL != pos->fds)
  1921. {
  1922. int del_result = scheduler_driver->del (scheduler_driver->cls, pos);
  1923. if (GNUNET_OK != del_result)
  1924. {
  1925. LOG (GNUNET_ERROR_TYPE_ERROR,
  1926. "driver could not delete task %p\n", pos);
  1927. GNUNET_assert (0);
  1928. }
  1929. }
  1930. active_task = NULL;
  1931. dump_backtrace (pos);
  1932. destroy_task (pos);
  1933. }
  1934. }
  1935. shutdown_if_no_lifeness ();
  1936. if (0 == ready_count)
  1937. {
  1938. scheduler_driver->set_wakeup (scheduler_driver->cls,
  1939. get_timeout ());
  1940. return GNUNET_NO;
  1941. }
  1942. scheduler_driver->set_wakeup (scheduler_driver->cls,
  1943. GNUNET_TIME_absolute_get ());
  1944. return GNUNET_YES;
  1945. }
  1946. /**
  1947. * Function called by external event loop implementations to initialize
  1948. * the scheduler. An external implementation has to provide @a driver
  1949. * which contains callbacks for the scheduler (see definition of struct
  1950. * #GNUNET_SCHEDULER_Driver). The callbacks are used to instruct the
  1951. * external implementation to watch for events. If it detects any of
  1952. * those events it is expected to call #GNUNET_SCHEDULER_do_work to let
  1953. * the scheduler handle it. If an event is related to a specific task
  1954. * (e.g. the scheduler gave instructions to watch a file descriptor),
  1955. * the external implementation is expected to mark that task ready
  1956. * before by calling #GNUNET_SCHEDULER_task_ready.
  1957. * This function has to be called before any tasks are scheduled and
  1958. * before GNUNET_SCHEDULER_do_work is called for the first time. It
  1959. * allocates resources that have to be freed again by calling
  1960. * #GNUNET_SCHEDULER_driver_done.
  1961. *
  1962. * This function installs the same signal handlers as
  1963. * #GNUNET_SCHEDULER_run. This means SIGTERM (and other similar signals)
  1964. * will induce a call to #GNUNET_SCHEDULER_shutdown during the next
  1965. * call to #GNUNET_SCHEDULER_do_work. As a result, SIGTERM causes all
  1966. * active tasks to be scheduled with reason
  1967. * #GNUNET_SCHEDULER_REASON_SHUTDOWN. (However, tasks added afterwards
  1968. * will execute normally!). Note that any particular signal will only
  1969. * shut down one scheduler; applications should always only create a
  1970. * single scheduler.
  1971. *
  1972. * @param driver to use for the event loop
  1973. * @return handle to be passed to #GNUNET_SCHEDULER_do_work and
  1974. * #GNUNET_SCHEDULER_driver_done
  1975. */
  1976. struct GNUNET_SCHEDULER_Handle *
  1977. GNUNET_SCHEDULER_driver_init (const struct GNUNET_SCHEDULER_Driver *driver)
  1978. {
  1979. struct GNUNET_SCHEDULER_Handle *sh;
  1980. const struct GNUNET_DISK_FileHandle *pr;
  1981. /* scheduler must not be running */
  1982. GNUNET_assert (NULL == scheduler_driver);
  1983. GNUNET_assert (NULL == shutdown_pipe_handle);
  1984. /* general set-up */
  1985. sh = GNUNET_new (struct GNUNET_SCHEDULER_Handle);
  1986. shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO,
  1987. GNUNET_NO,
  1988. GNUNET_NO,
  1989. GNUNET_NO);
  1990. GNUNET_assert (NULL != shutdown_pipe_handle);
  1991. pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle,
  1992. GNUNET_DISK_PIPE_END_READ);
  1993. my_pid = getpid ();
  1994. scheduler_driver = driver;
  1995. /* install signal handlers */
  1996. LOG (GNUNET_ERROR_TYPE_DEBUG,
  1997. "Registering signal handlers\n");
  1998. sh->shc_int = GNUNET_SIGNAL_handler_install (SIGINT,
  1999. &sighandler_shutdown);
  2000. sh->shc_term = GNUNET_SIGNAL_handler_install (SIGTERM,
  2001. &sighandler_shutdown);
  2002. #if (SIGTERM != GNUNET_TERM_SIG)
  2003. sh->shc_gterm = GNUNET_SIGNAL_handler_install (GNUNET_TERM_SIG,
  2004. &sighandler_shutdown);
  2005. #endif
  2006. sh->shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE,
  2007. &sighandler_pipe);
  2008. sh->shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT,
  2009. &sighandler_shutdown);
  2010. sh->shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP,
  2011. &sighandler_shutdown);
  2012. /* Setup initial tasks */
  2013. current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
  2014. current_lifeness = GNUNET_NO;
  2015. install_parent_control_task =
  2016. GNUNET_SCHEDULER_add_now (&install_parent_control_handler,
  2017. NULL);
  2018. shutdown_pipe_task =
  2019. GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
  2020. pr,
  2021. &shutdown_pipe_cb,
  2022. NULL);
  2023. current_lifeness = GNUNET_YES;
  2024. scheduler_driver->set_wakeup (scheduler_driver->cls,
  2025. get_timeout ());
  2026. /* begin main event loop */
  2027. sh->rs = GNUNET_NETWORK_fdset_create ();
  2028. sh->ws = GNUNET_NETWORK_fdset_create ();
  2029. GNUNET_NETWORK_fdset_handle_set (sh->rs, pr);
  2030. return sh;
  2031. }
  2032. /**
  2033. * Counter-part of #GNUNET_SCHEDULER_driver_init. Has to be called
  2034. * by external event loop implementations after the scheduler has
  2035. * shut down. This is the case if both of the following conditions
  2036. * are met:
  2037. *
  2038. * - all tasks the scheduler has added through the driver's add
  2039. * callback have been removed again through the driver's del
  2040. * callback
  2041. * - the timeout the scheduler has set through the driver's
  2042. * add_wakeup callback is FOREVER
  2043. *
  2044. * @param sh the handle returned by #GNUNET_SCHEDULER_driver_init
  2045. */
  2046. void
  2047. GNUNET_SCHEDULER_driver_done (struct GNUNET_SCHEDULER_Handle *sh)
  2048. {
  2049. GNUNET_assert (NULL == pending_head);
  2050. GNUNET_assert (NULL == pending_timeout_head);
  2051. GNUNET_assert (NULL == shutdown_head);
  2052. for (int i = 0; i != GNUNET_SCHEDULER_PRIORITY_COUNT; ++i)
  2053. {
  2054. GNUNET_assert (NULL == ready_head[i]);
  2055. }
  2056. GNUNET_NETWORK_fdset_destroy (sh->rs);
  2057. GNUNET_NETWORK_fdset_destroy (sh->ws);
  2058. /* uninstall signal handlers */
  2059. GNUNET_SIGNAL_handler_uninstall (sh->shc_int);
  2060. GNUNET_SIGNAL_handler_uninstall (sh->shc_term);
  2061. #if (SIGTERM != GNUNET_TERM_SIG)
  2062. GNUNET_SIGNAL_handler_uninstall (sh->shc_gterm);
  2063. #endif
  2064. GNUNET_SIGNAL_handler_uninstall (sh->shc_pipe);
  2065. GNUNET_SIGNAL_handler_uninstall (sh->shc_quit);
  2066. GNUNET_SIGNAL_handler_uninstall (sh->shc_hup);
  2067. GNUNET_DISK_pipe_close (shutdown_pipe_handle);
  2068. shutdown_pipe_handle = NULL;
  2069. scheduler_driver = NULL;
  2070. GNUNET_free (sh);
  2071. }
  2072. static int
  2073. select_loop (struct GNUNET_SCHEDULER_Handle *sh,
  2074. struct DriverContext *context)
  2075. {
  2076. struct GNUNET_NETWORK_FDSet *rs;
  2077. struct GNUNET_NETWORK_FDSet *ws;
  2078. int select_result;
  2079. GNUNET_assert (NULL != context);
  2080. rs = GNUNET_NETWORK_fdset_create ();
  2081. ws = GNUNET_NETWORK_fdset_create ();
  2082. while ((NULL != context->scheduled_head) ||
  2083. (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
  2084. context->timeout.abs_value_us))
  2085. {
  2086. LOG (GNUNET_ERROR_TYPE_DEBUG,
  2087. "select timeout = %s\n",
  2088. GNUNET_STRINGS_absolute_time_to_string (context->timeout));
  2089. GNUNET_NETWORK_fdset_zero (rs);
  2090. GNUNET_NETWORK_fdset_zero (ws);
  2091. for (struct Scheduled *pos = context->scheduled_head;
  2092. NULL != pos;
  2093. pos = pos->next)
  2094. {
  2095. if (0 != (GNUNET_SCHEDULER_ET_IN & pos->et))
  2096. {
  2097. GNUNET_NETWORK_fdset_set_native (rs, pos->fdi->sock);
  2098. }
  2099. if (0 != (GNUNET_SCHEDULER_ET_OUT & pos->et))
  2100. {
  2101. GNUNET_NETWORK_fdset_set_native (ws, pos->fdi->sock);
  2102. }
  2103. }
  2104. struct GNUNET_TIME_Relative time_remaining =
  2105. GNUNET_TIME_absolute_get_remaining (context->timeout);
  2106. if (NULL == scheduler_select)
  2107. {
  2108. select_result = GNUNET_NETWORK_socket_select (rs,
  2109. ws,
  2110. NULL,
  2111. time_remaining);
  2112. }
  2113. else
  2114. {
  2115. select_result = scheduler_select (scheduler_select_cls,
  2116. rs,
  2117. ws,
  2118. NULL,
  2119. time_remaining);
  2120. }
  2121. if (select_result == GNUNET_SYSERR)
  2122. {
  2123. if (errno == EINTR)
  2124. continue;
  2125. LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
  2126. "select");
  2127. #if USE_LSOF
  2128. char lsof[512];
  2129. snprintf (lsof,
  2130. sizeof(lsof),
  2131. "lsof -p %d",
  2132. getpid ());
  2133. (void) close (1);
  2134. (void) dup2 (2, 1);
  2135. if (0 != system (lsof))
  2136. LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
  2137. "system");
  2138. #endif
  2139. #if DEBUG_FDS
  2140. for (struct Scheduled *s = context->scheduled_head;
  2141. NULL != s;
  2142. s = s->next)
  2143. {
  2144. int flags = fcntl (s->fdi->sock,
  2145. F_GETFD);
  2146. if ((flags == -1) &&
  2147. (EBADF == errno))
  2148. {
  2149. LOG (GNUNET_ERROR_TYPE_ERROR,
  2150. "Got invalid file descriptor %d!\n",
  2151. s->fdi->sock);
  2152. #if EXECINFO
  2153. dump_backtrace (s->task);
  2154. #endif
  2155. }
  2156. }
  2157. #endif
  2158. GNUNET_assert (0);
  2159. GNUNET_NETWORK_fdset_destroy (rs);
  2160. GNUNET_NETWORK_fdset_destroy (ws);
  2161. return GNUNET_SYSERR;
  2162. }
  2163. if (select_result > 0)
  2164. {
  2165. for (struct Scheduled *pos = context->scheduled_head;
  2166. NULL != pos;
  2167. pos = pos->next)
  2168. {
  2169. int is_ready = GNUNET_NO;
  2170. if ((0 != (GNUNET_SCHEDULER_ET_IN & pos->et)) &&
  2171. (GNUNET_YES ==
  2172. GNUNET_NETWORK_fdset_test_native (rs,
  2173. pos->fdi->sock)) )
  2174. {
  2175. pos->fdi->et |= GNUNET_SCHEDULER_ET_IN;
  2176. is_ready = GNUNET_YES;
  2177. }
  2178. if ((0 != (GNUNET_SCHEDULER_ET_OUT & pos->et)) &&
  2179. (GNUNET_YES ==
  2180. GNUNET_NETWORK_fdset_test_native (ws,
  2181. pos->fdi->sock)) )
  2182. {
  2183. pos->fdi->et |= GNUNET_SCHEDULER_ET_OUT;
  2184. is_ready = GNUNET_YES;
  2185. }
  2186. if (GNUNET_YES == is_ready)
  2187. {
  2188. GNUNET_SCHEDULER_task_ready (pos->task,
  2189. pos->fdi);
  2190. }
  2191. }
  2192. }
  2193. if (GNUNET_YES == GNUNET_SCHEDULER_do_work (sh))
  2194. {
  2195. LOG (GNUNET_ERROR_TYPE_DEBUG,
  2196. "scheduler has more tasks ready!\n");
  2197. }
  2198. }
  2199. GNUNET_NETWORK_fdset_destroy (rs);
  2200. GNUNET_NETWORK_fdset_destroy (ws);
  2201. return GNUNET_OK;
  2202. }
  2203. static int
  2204. select_add (void *cls,
  2205. struct GNUNET_SCHEDULER_Task *task,
  2206. struct GNUNET_SCHEDULER_FdInfo *fdi)
  2207. {
  2208. struct DriverContext *context = cls;
  2209. GNUNET_assert (NULL != context);
  2210. GNUNET_assert (NULL != task);
  2211. GNUNET_assert (NULL != fdi);
  2212. GNUNET_assert (0 != (GNUNET_SCHEDULER_ET_IN & fdi->et) ||
  2213. 0 != (GNUNET_SCHEDULER_ET_OUT & fdi->et));
  2214. if (! ((NULL != fdi->fd) ^ (NULL != fdi->fh)) || (fdi->sock < 0))
  2215. {
  2216. /* exactly one out of {fd, hf} must be != NULL and the OS handle must be valid */
  2217. return GNUNET_SYSERR;
  2218. }
  2219. struct Scheduled *scheduled = GNUNET_new (struct Scheduled);
  2220. scheduled->task = task;
  2221. scheduled->fdi = fdi;
  2222. scheduled->et = fdi->et;
  2223. GNUNET_CONTAINER_DLL_insert (context->scheduled_head,
  2224. context->scheduled_tail,
  2225. scheduled);
  2226. return GNUNET_OK;
  2227. }
  2228. static int
  2229. select_del (void *cls,
  2230. struct GNUNET_SCHEDULER_Task *task)
  2231. {
  2232. struct DriverContext *context;
  2233. struct Scheduled *pos;
  2234. int ret;
  2235. GNUNET_assert (NULL != cls);
  2236. context = cls;
  2237. ret = GNUNET_SYSERR;
  2238. pos = context->scheduled_head;
  2239. while (NULL != pos)
  2240. {
  2241. struct Scheduled *next = pos->next;
  2242. if (pos->task == task)
  2243. {
  2244. GNUNET_CONTAINER_DLL_remove (context->scheduled_head,
  2245. context->scheduled_tail,
  2246. pos);
  2247. GNUNET_free (pos);
  2248. ret = GNUNET_OK;
  2249. }
  2250. pos = next;
  2251. }
  2252. return ret;
  2253. }
  2254. static void
  2255. select_set_wakeup (void *cls,
  2256. struct GNUNET_TIME_Absolute dt)
  2257. {
  2258. struct DriverContext *context = cls;
  2259. GNUNET_assert (NULL != context);
  2260. context->timeout = dt;
  2261. }
  2262. /**
  2263. * Obtain the driver for using select() as the event loop.
  2264. *
  2265. * @return NULL on error
  2266. */
  2267. struct GNUNET_SCHEDULER_Driver *
  2268. GNUNET_SCHEDULER_driver_select ()
  2269. {
  2270. struct GNUNET_SCHEDULER_Driver *select_driver;
  2271. select_driver = GNUNET_new (struct GNUNET_SCHEDULER_Driver);
  2272. select_driver->add = &select_add;
  2273. select_driver->del = &select_del;
  2274. select_driver->set_wakeup = &select_set_wakeup;
  2275. return select_driver;
  2276. }
  2277. /**
  2278. * Change the async scope for the currently executing task and (transitively)
  2279. * for all tasks scheduled by the current task after calling this function.
  2280. * Nested tasks can begin their own nested async scope.
  2281. *
  2282. * Once the current task is finished, the async scope ID is reset to
  2283. * its previous value.
  2284. *
  2285. * Must only be called from a running task.
  2286. *
  2287. * @param aid the asynchronous scope id to enter
  2288. */
  2289. void
  2290. GNUNET_SCHEDULER_begin_async_scope (struct GNUNET_AsyncScopeId *aid)
  2291. {
  2292. struct GNUNET_AsyncScopeSave dummy_old_scope;
  2293. GNUNET_assert (NULL != active_task);
  2294. /* Since we're in a task, the context will be automatically
  2295. restored by the scheduler. */
  2296. GNUNET_async_scope_enter (aid, &dummy_old_scope);
  2297. }
  2298. /* end of scheduler.c */