1 /*
2 * include/proto/applet.h
3 * This file contains applet function prototypes
4 *
5 * Copyright (C) 2000-2015 Willy Tarreau - w@1wt.eu
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation, version 2.1
10 * exclusively.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #ifndef _PROTO_APPLET_H
23 #define _PROTO_APPLET_H
24
25 #include <stdlib.h>
26
27 #include <common/config.h>
28 #include <common/mini-clist.h>
29 #include <types/applet.h>
30 #include <proto/connection.h>
31
32 extern unsigned int nb_applets;
33 extern unsigned long active_applets_mask;
34 extern unsigned int applets_active_queue;
35 __decl_hathreads(extern HA_SPINLOCK_T applet_active_lock);
36 extern struct list applet_active_queue;
37
38 void applet_run_active();
39
40
41 static int inline appctx_res_wakeup(struct appctx *appctx);
42
43
44 /* Initializes all required fields for a new appctx. Note that it does the
45 * minimum acceptable initialization for an appctx. This means only the
46 * 3 integer states st0, st1, st2 are zeroed.
47 */
appctx_init(struct appctx * appctx,unsigned long thread_mask)48 static inline void appctx_init(struct appctx *appctx, unsigned long thread_mask)
49 {
50 appctx->st0 = appctx->st1 = appctx->st2 = 0;
51 appctx->io_release = NULL;
52 appctx->thread_mask = thread_mask;
53 appctx->state = APPLET_SLEEPING;
54 }
55
56 /* Tries to allocate a new appctx and initialize its main fields. The appctx
57 * is returned on success, NULL on failure. The appctx must be released using
58 * pool_free(connection) or appctx_free(), since it's allocated from the
59 * connection pool. <applet> is assigned as the applet, but it can be NULL.
60 */
appctx_new(struct applet * applet,unsigned long thread_mask)61 static inline struct appctx *appctx_new(struct applet *applet, unsigned long thread_mask)
62 {
63 struct appctx *appctx;
64
65 appctx = pool_alloc(pool_head_connection);
66 if (likely(appctx != NULL)) {
67 appctx->obj_type = OBJ_TYPE_APPCTX;
68 appctx->applet = applet;
69 appctx_init(appctx, thread_mask);
70 LIST_INIT(&appctx->runq);
71 LIST_INIT(&appctx->buffer_wait.list);
72 appctx->buffer_wait.target = appctx;
73 appctx->buffer_wait.wakeup_cb = (int (*)(void *))appctx_res_wakeup;
74 HA_ATOMIC_ADD(&nb_applets, 1);
75 }
76 return appctx;
77 }
78
79 /* Releases an appctx previously allocated by appctx_new(). Note that
80 * we share the connection pool.
81 */
__appctx_free(struct appctx * appctx)82 static inline void __appctx_free(struct appctx *appctx)
83 {
84 if (!LIST_ISEMPTY(&appctx->runq)) {
85 LIST_DEL(&appctx->runq);
86 applets_active_queue--;
87 }
88
89 if (!LIST_ISEMPTY(&appctx->buffer_wait.list)) {
90 HA_SPIN_LOCK(BUF_WQ_LOCK, &buffer_wq_lock);
91 LIST_DEL(&appctx->buffer_wait.list);
92 LIST_INIT(&appctx->buffer_wait.list);
93 HA_SPIN_UNLOCK(BUF_WQ_LOCK, &buffer_wq_lock);
94 }
95
96 pool_free(pool_head_connection, appctx);
97 HA_ATOMIC_SUB(&nb_applets, 1);
98 }
appctx_free(struct appctx * appctx)99 static inline void appctx_free(struct appctx *appctx)
100 {
101 HA_SPIN_LOCK(APPLETS_LOCK, &applet_active_lock);
102 if (appctx->state & APPLET_RUNNING) {
103 appctx->state |= APPLET_WANT_DIE;
104 HA_SPIN_UNLOCK(APPLETS_LOCK, &applet_active_lock);
105 return;
106 }
107 __appctx_free(appctx);
108 HA_SPIN_UNLOCK(APPLETS_LOCK, &applet_active_lock);
109 }
110
111 /* wakes up an applet when conditions have changed */
__appctx_wakeup(struct appctx * appctx)112 static inline void __appctx_wakeup(struct appctx *appctx)
113 {
114 if (LIST_ISEMPTY(&appctx->runq)) {
115 LIST_ADDQ(&applet_active_queue, &appctx->runq);
116 applets_active_queue++;
117 active_applets_mask |= appctx->thread_mask;
118 }
119 }
120
appctx_wakeup(struct appctx * appctx)121 static inline void appctx_wakeup(struct appctx *appctx)
122 {
123 HA_SPIN_LOCK(APPLETS_LOCK, &applet_active_lock);
124 if (appctx->state & APPLET_RUNNING) {
125 appctx->state |= APPLET_WOKEN_UP;
126 HA_SPIN_UNLOCK(APPLETS_LOCK, &applet_active_lock);
127 return;
128 }
129 __appctx_wakeup(appctx);
130 HA_SPIN_UNLOCK(APPLETS_LOCK, &applet_active_lock);
131 }
132
133 /* Callback used to wake up an applet when a buffer is available. The applet
134 * <appctx> is woken up is if it is not already in the list of "active"
135 * applets. This functions returns 1 is the stream is woken up, otherwise it
136 * returns 0. If task is running we request we check if woken was already
137 * requested */
appctx_res_wakeup(struct appctx * appctx)138 static inline int appctx_res_wakeup(struct appctx *appctx)
139 {
140 HA_SPIN_LOCK(APPLETS_LOCK, &applet_active_lock);
141 if (appctx->state & APPLET_RUNNING) {
142 if (appctx->state & APPLET_WOKEN_UP) {
143 HA_SPIN_UNLOCK(APPLETS_LOCK, &applet_active_lock);
144 return 0;
145 }
146 appctx->state |= APPLET_WOKEN_UP;
147 HA_SPIN_UNLOCK(APPLETS_LOCK, &applet_active_lock);
148 return 1;
149 }
150 __appctx_wakeup(appctx);
151 HA_SPIN_UNLOCK(APPLETS_LOCK, &applet_active_lock);
152 return 1;
153 }
154
155
156 #endif /* _PROTO_APPLET_H */
157
158 /*
159 * Local variables:
160 * c-indent-level: 8
161 * c-basic-offset: 8
162 * End:
163 */
164