blob: 77f984d91f75c3e703c4c785e14c899c4faa9ad7 [file] [log] [blame]
Willy Tarreau81f38d62015-04-13 17:11:11 +02001/*
2 * Functions managing applets
3 *
4 * Copyright 2000-2015 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15
16#include <common/config.h>
17#include <common/mini-clist.h>
18#include <proto/applet.h>
Christopher Fauleta73e59b2016-12-09 17:30:18 +010019#include <proto/channel.h>
Willy Tarreau3c595ac2015-04-19 09:59:31 +020020#include <proto/stream.h>
21#include <proto/stream_interface.h>
Willy Tarreau81f38d62015-04-13 17:11:11 +020022
Christopher Faulet1cbe74c2016-12-06 09:13:22 +010023unsigned int nb_applets = 0;
Christopher Faulet595d7b72017-11-14 11:28:52 +010024unsigned long active_applets_mask = 0;
Christopher Faulet1cbe74c2016-12-06 09:13:22 +010025unsigned int applets_active_queue = 0;
Christopher Faulet9dcf9b62017-11-13 10:34:01 +010026__decl_hathreads(HA_SPINLOCK_T applet_active_lock); /* spin lock related to applet active queue */
Emeric Brun1138fd02017-06-19 12:38:55 +020027
Willy Tarreau64bca9d2015-09-25 17:39:23 +020028struct list applet_active_queue = LIST_HEAD_INIT(applet_active_queue);
Willy Tarreau3c595ac2015-04-19 09:59:31 +020029
30void applet_run_active()
31{
Emeric Brunc7306062017-06-26 16:36:53 +020032 struct appctx *curr, *next;
Willy Tarreau3c595ac2015-04-19 09:59:31 +020033 struct stream_interface *si;
Emeric Brunc7306062017-06-26 16:36:53 +020034 struct list applet_cur_queue = LIST_HEAD_INIT(applet_cur_queue);
Christopher Fauletb4a4d9a2017-11-15 22:14:49 +010035 int max_processed;
36
37 max_processed = applets_active_queue;
38 if (max_processed > 200)
39 max_processed = 200;
Willy Tarreau3c595ac2015-04-19 09:59:31 +020040
Christopher Faulet2a944ee2017-11-07 10:42:54 +010041 HA_SPIN_LOCK(APPLETS_LOCK, &applet_active_lock);
Christopher Faulet71630562017-11-14 11:30:47 +010042 if (!(active_applets_mask & tid_bit)) {
43 HA_SPIN_UNLOCK(APPLETS_LOCK, &applet_active_lock);
44 return;
45 }
Christopher Fauletb4a4d9a2017-11-15 22:14:49 +010046 active_applets_mask &= ~tid_bit;
Emeric Brunc7306062017-06-26 16:36:53 +020047 curr = LIST_NEXT(&applet_active_queue, typeof(curr), runq);
48 while (&curr->runq != &applet_active_queue) {
49 next = LIST_NEXT(&curr->runq, typeof(next), runq);
Willy Tarreauf65610a2017-10-31 16:06:06 +010050 if (curr->thread_mask & tid_bit) {
Emeric Brun1138fd02017-06-19 12:38:55 +020051 LIST_DEL(&curr->runq);
52 curr->state = APPLET_RUNNING;
53 LIST_ADDQ(&applet_cur_queue, &curr->runq);
54 applets_active_queue--;
Christopher Fauletb4a4d9a2017-11-15 22:14:49 +010055 max_processed--;
Emeric Brun1138fd02017-06-19 12:38:55 +020056 }
Emeric Brunc7306062017-06-26 16:36:53 +020057 curr = next;
Christopher Fauletb4a4d9a2017-11-15 22:14:49 +010058 if (max_processed <= 0) {
59 active_applets_mask |= tid_bit;
60 break;
61 }
Emeric Brunc7306062017-06-26 16:36:53 +020062 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +010063 HA_SPIN_UNLOCK(APPLETS_LOCK, &applet_active_lock);
Emeric Brun1138fd02017-06-19 12:38:55 +020064
Willy Tarreau99942382015-09-25 17:56:16 +020065 /* The list is only scanned from the head. This guarantees that if any
66 * applet removes another one, there is no side effect while walking
67 * through the list.
68 */
Christopher Faulet1cbe74c2016-12-06 09:13:22 +010069 while (!LIST_ISEMPTY(&applet_cur_queue)) {
70 curr = LIST_ELEM(applet_cur_queue.n, typeof(curr), runq);
Willy Tarreau3c595ac2015-04-19 09:59:31 +020071 si = curr->owner;
72
Christopher Fauleta73e59b2016-12-09 17:30:18 +010073 /* Now we'll try to allocate the input buffer. We wake up the
74 * applet in all cases. So this is the applet responsibility to
75 * check if this buffer was allocated or not. This let a chance
76 * for applets to do some other processing if needed. */
77 if (!channel_alloc_buffer(si_ic(si), &curr->buffer_wait))
78 si_applet_cant_put(si);
Willy Tarreau3c595ac2015-04-19 09:59:31 +020079
Willy Tarreaufe127932015-04-21 19:23:39 +020080 /* We always pretend the applet can't get and doesn't want to
81 * put, it's up to it to change this if needed. This ensures
82 * that one applet which ignores any event will not spin.
83 */
84 si_applet_cant_get(si);
85 si_applet_stop_put(si);
86
Willy Tarreau3c595ac2015-04-19 09:59:31 +020087 curr->applet->fct(curr);
Willy Tarreauaa977ba2015-09-25 11:45:06 +020088 si_applet_wake_cb(si);
Christopher Fauleta73e59b2016-12-09 17:30:18 +010089 channel_release_buffer(si_ic(si), &curr->buffer_wait);
Willy Tarreau99942382015-09-25 17:56:16 +020090
Christopher Faulet1cbe74c2016-12-06 09:13:22 +010091 if (applet_cur_queue.n == &curr->runq) {
Willy Tarreau99942382015-09-25 17:56:16 +020092 /* curr was left in the list, move it back to the active list */
93 LIST_DEL(&curr->runq);
Emeric Brunc7306062017-06-26 16:36:53 +020094 LIST_INIT(&curr->runq);
Christopher Faulet2a944ee2017-11-07 10:42:54 +010095 HA_SPIN_LOCK(APPLETS_LOCK, &applet_active_lock);
Emeric Brunc7306062017-06-26 16:36:53 +020096 if (curr->state & APPLET_WANT_DIE) {
97 curr->state = APPLET_SLEEPING;
98 __appctx_free(curr);
99 }
100 else {
101 if (curr->state & APPLET_WOKEN_UP) {
102 curr->state = APPLET_SLEEPING;
103 __appctx_wakeup(curr);
104 }
105 else {
106 curr->state = APPLET_SLEEPING;
107 }
108 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100109 HA_SPIN_UNLOCK(APPLETS_LOCK, &applet_active_lock);
Willy Tarreau99942382015-09-25 17:56:16 +0200110 }
Willy Tarreau3c595ac2015-04-19 09:59:31 +0200111 }
112}
Emeric Brun1138fd02017-06-19 12:38:55 +0200113
114__attribute__((constructor))
115static void __applet_init(void)
116{
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100117 HA_SPIN_INIT(&applet_active_lock);
Emeric Brun1138fd02017-06-19 12:38:55 +0200118}