00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <config.h>
00036
00037 #include <string.h>
00038 #include "lwp.h"
00039 #include "lwpint.h"
00040 #include "prototypes.h"
00041
00042 struct lwpQueue LwpSchedQ[LWP_MAX_PRIO], LwpDeadQ;
00043
00044 struct lwpProc *LwpCurrent = NULL;
00045 void **LwpContextPtr;
00046 int LwpMaxpri = 0;
00047 int LwpStackGrowsDown;
00048
00049 static void lwpDestroy(struct lwpProc *proc);
00050 static void lwpStackCheckInit(struct lwpProc *newp);
00051 static void lwpStackCheck(struct lwpProc *newp);
00052 static void lwpStackCheckUsed(struct lwpProc *newp);
00053
00054
00055 static int
00056 growsdown(void *x)
00057 {
00058 int y;
00059 y = (x > (void *)&y);
00060 return y;
00061 }
00062
00063
00064
00065
00066
00067 void
00068 lwpReschedule(void)
00069 {
00070 static struct lwpProc *nextp;
00071 static int i;
00072
00073 if (LwpCurrent && (LwpCurrent->flags & LWP_STACKCHECK)) {
00074 lwpStackCheck(LwpCurrent);
00075 }
00076
00077 lwpSigWakeup();
00078 lwpWakeupSleep();
00079
00080
00081 lwpStatus(LwpCurrent, "Cleaning dead queue");
00082 while (NULL != (nextp = lwpGetFirst(&LwpDeadQ))) {
00083 if (CANT_HAPPEN(nextp == LwpCurrent))
00084 abort();
00085 lwpDestroy(nextp);
00086 lwpStatus(LwpCurrent, "Destroying done");
00087 }
00088
00089 for (i = LwpMaxpri + 1; i--;) {
00090 while (NULL != (nextp = lwpGetFirst(&LwpSchedQ[i]))) {
00091 if (!nextp->dead)
00092 break;
00093
00094 lwpStatus(nextp, "got a dead body");
00095 if (nextp == LwpCurrent) {
00096 lwpStatus(nextp, "we are in it -- will bury later");
00097 lwpAddTail(&LwpDeadQ, nextp);
00098 } else {
00099 lwpDestroy(nextp);
00100 }
00101 nextp = 0;
00102 }
00103 if (nextp)
00104 break;
00105 }
00106 if (CANT_HAPPEN(LwpCurrent == 0 && nextp == 0))
00107 abort();
00108 if (LwpCurrent != nextp) {
00109 struct lwpProc *oldp = LwpCurrent;
00110 if (oldp)
00111 lwpStatus(oldp, "switch out");
00112 LwpCurrent = nextp;
00113 *LwpContextPtr = nextp->ud;
00114 lwpSwitchContext(oldp, nextp);
00115 lwpStatus(nextp, "switch in %d", nextp->pri);
00116 }
00117 }
00118
00119
00120
00121
00122 void
00123 lwpEntryPoint(void)
00124 {
00125 lwpStatus(LwpCurrent, "starting at entry point");
00126 (*LwpCurrent->entry)(LwpCurrent->ud);
00127 lwpExit();
00128 }
00129
00130
00131
00132
00133 struct lwpProc *
00134 lwpCreate(int priority, void (*entry)(void *), int stacksz,
00135 int flags, char *name, int argc, char **argv, void *ud)
00136 {
00137 struct lwpProc *newp;
00138
00139 if (!(newp = malloc(sizeof(struct lwpProc))))
00140 return NULL;
00141 newp->flags = flags;
00142 newp->name = strdup(name);
00143 newp->entry = entry;
00144 newp->argc = argc;
00145 newp->argv = argv;
00146 newp->ud = ud;
00147 newp->dead = 0;
00148 newp->runtime = (time_t)-1;
00149 newp->fd = -1;
00150 if (LWP_MAX_PRIO <= priority)
00151 priority = LWP_MAX_PRIO - 1;
00152 if (LwpMaxpri < (newp->pri = priority))
00153 LwpMaxpri = priority;
00154 if (lwpNewContext(newp, stacksz) < 0) {
00155 free(newp->name);
00156 free(newp);
00157 return NULL;
00158 }
00159 lwpStatus(newp, "creating process structure %p (sbtm %p)",
00160 newp, newp->sbtm);
00161 if (flags & LWP_STACKCHECK)
00162 lwpStackCheckInit(newp);
00163 lwpReady(newp);
00164 lwpReady(LwpCurrent);
00165 lwpReschedule();
00166 return newp;
00167 }
00168
00169 static void
00170 lwpDestroy(struct lwpProc *proc)
00171 {
00172 if (proc->flags & LWP_STACKCHECK) {
00173 lwpStackCheckUsed(proc);
00174 lwpStackCheck(proc);
00175 }
00176 lwpStatus(proc, "destroying sbtm: %p", proc->sbtm);
00177 free(proc->sbtm);
00178 free(proc->name);
00179 free(proc);
00180 }
00181
00182
00183
00184
00185 void
00186 lwpReady(struct lwpProc *p)
00187 {
00188 if (!p)
00189 p = LwpCurrent;
00190 lwpStatus(p, "added to run queue");
00191 lwpAddTail(&LwpSchedQ[p->pri], p);
00192 }
00193
00194
00195
00196
00197 void *
00198 lwpGetUD(struct lwpProc *p)
00199 {
00200 if (!p)
00201 p = LwpCurrent;
00202 return p->ud;
00203 }
00204
00205
00206
00207
00208 void
00209 lwpSetUD(struct lwpProc *p, char *ud)
00210 {
00211 if (!p)
00212 p = LwpCurrent;
00213 p->ud = ud;
00214 }
00215
00216
00217
00218
00219 void
00220 lwpYield(void)
00221 {
00222 lwpStatus(LwpCurrent, "yielding control");
00223 lwpReady(LwpCurrent);
00224 lwpReschedule();
00225 }
00226
00227
00228
00229
00230 void
00231 lwpExit(void)
00232 {
00233 lwpStatus(LwpCurrent, "marking self as dead");
00234 LwpCurrent->dead = 1;
00235 lwpYield();
00236 }
00237
00238
00239
00240
00241
00242 void
00243 lwpTerminate(struct lwpProc *p)
00244 {
00245 lwpStatus(p, "terminating process");
00246 p->dead = 1;
00247 lwpWakeup(p);
00248 }
00249
00250
00251
00252
00253
00254 int
00255 lwpSetPriority(int new)
00256 {
00257 int old = LwpCurrent->pri;
00258
00259 if (LWP_MAX_PRIO <= new)
00260 new = LWP_MAX_PRIO - 1;
00261 if (LwpMaxpri < new)
00262 LwpMaxpri = new;
00263 LwpCurrent->pri = new;
00264 lwpStatus(LwpCurrent, "resetting priority (%d -> %d)", old, new);
00265 if (new < old)
00266 lwpYield();
00267 return old;
00268 }
00269
00270
00271
00272
00273 struct lwpProc *
00274 lwpInitSystem(int pri, void **ctxptr, int flags, sigset_t *waitset)
00275 {
00276 struct lwpQueue *q;
00277 int i, *stack, marker;
00278 struct lwpProc *sel;
00279
00280 LwpContextPtr = ctxptr;
00281 if (pri < 1)
00282 pri = 1;
00283 LwpStackGrowsDown = growsdown(&marker);
00284 if (!(LwpCurrent = calloc(1, sizeof(struct lwpProc))))
00285 return NULL;
00286 if (!(stack = malloc(64)))
00287 return NULL;
00288 if (LWP_MAX_PRIO <= pri)
00289 pri = LWP_MAX_PRIO - 1;
00290 if (LwpMaxpri < pri)
00291 LwpMaxpri = pri;
00292 LwpCurrent->next = 0;
00293 LwpCurrent->sbtm = stack;
00294 LwpCurrent->pri = pri;
00295 LwpCurrent->dead = 0;
00296 LwpCurrent->flags = flags & ~LWP_STACKCHECK;
00297 LwpCurrent->name = "Main";
00298 for (i = LWP_MAX_PRIO, q = LwpSchedQ; i--; q++)
00299 q->head = q->tail = 0;
00300 LwpDeadQ.head = LwpDeadQ.tail = 0;
00301 lwpInitSigWait(waitset);
00302
00303 sel = lwpCreate(0, lwpSelect, 16384, flags, "EventHandler", 0, 0, 0);
00304 lwpInitSelect(sel);
00305 return LwpCurrent;
00306 }
00307
00308
00309
00310
00311
00312
00313
00314 static void
00315 lwpStackCheckInit(struct lwpProc *newp)
00316 {
00317 int *p;
00318 int *lim = (int *)((char *)newp->sbtm + newp->size);
00319
00320 for (p = newp->sbtm; p < lim; p++)
00321 *p = LWP_CHECKMARK;
00322 }
00323
00324
00325
00326
00327
00328
00329 static void
00330 lwpStackCheck(struct lwpProc *newp)
00331 {
00332 int *btm = (int *)(newp->ustack - LWP_REDZONE);
00333 int *top = (int *)(newp->ustack + newp->usize + LWP_REDZONE);
00334 int n = LWP_REDZONE / sizeof(int);
00335 int i, lo_clean, hi_clean, overflow, underflow;
00336
00337 for (i = 0; i < n && btm[i] == LWP_CHECKMARK; i++) ;
00338 lo_clean = i;
00339
00340 for (i = 1; i <= n && top[-i] == LWP_CHECKMARK; i++) ;
00341 hi_clean = i - 1;
00342
00343 if (LwpStackGrowsDown) {
00344 overflow = n - lo_clean;
00345 underflow = n - hi_clean;
00346 } else {
00347 overflow = n - hi_clean;
00348 underflow = n - lo_clean;
00349 }
00350 if (overflow)
00351 logerror("Thread %s stack overflow %d bytes",
00352 newp->name, overflow * (int)sizeof(int));
00353 if (underflow)
00354 logerror("Thread %s stack underflow %d bytes",
00355 newp->name, underflow * (int)sizeof(int));
00356 if (overflow || underflow)
00357 abort();
00358 }
00359
00360
00361
00362
00363
00364 static void
00365 lwpStackCheckUsed(struct lwpProc *newp)
00366 {
00367 int *base = (int *)newp->ustack;
00368 int *lim = (int *)(newp->ustack + newp->usize);
00369 int total = (lim + 1 - base) * sizeof(int);
00370 int used, *p;
00371
00372 if (LwpStackGrowsDown) {
00373 for (p = base; p < lim && *p == LWP_CHECKMARK; ++p) ;
00374 used = (lim - p) * sizeof(int);
00375 } else {
00376 for (p = lim - 1; p >= base && *p == LWP_CHECKMARK; --p) ;
00377 used = (p - base + 1) * sizeof(int);
00378 }
00379 lwpStatus(newp, "Thread stack %d used, %d left, %d total",
00380 used, total - used, total);
00381 }