Statistics
| Branch: | Revision:

root / src / sim / task.cc @ e1750c09

History | View | Annotate | Download (5.88 KB)

1
//========================================================================
2
//  TASK.CC - part of
3
//
4
//                 OMNeT++/OMNEST
5
//              Discrete System Simulation in C++
6
//
7
//  Author: Andras Varga
8
//          based on Stig Kofoed's portable coroutines, see the Manual
9
//========================================================================
10

    
11
/*--------------------------------------------------------------*
12
  Copyright (C) 1992-2008 Andras Varga
13
  Copyright (C) 2006-2008 OpenSim Ltd.
14

15
  This file is distributed WITHOUT ANY WARRANTY. See the file
16
  `license' for details on this and other legal matters.
17
*--------------------------------------------------------------*/
18

    
19
#include <string.h>
20
#include "task.h"
21

    
22
NAMESPACE_BEGIN
23

    
24
_Task main_task;
25
_Task *current_task = NULL;
26
JMP_BUF tmp_jmpb;
27

    
28
unsigned dist( _Task *from, _Task *to )
29
{
30
    char *c1 = (char *) from,
31
         *c2 = (char *) to;
32

    
33
    return (unsigned)( c1>c2 ? c1-c2 : c2-c1 );
34
}
35

    
36
void eat( _Task *p, unsigned size, _Task *prevbeef )
37
{
38
    unsigned d;
39
    _Task t;
40

    
41
    /* This function does the lion's share of the job. */
42
    /* Never returns!  p: caller task */
43

    
44
    /* init beef */
45
    t.guardbeef1 = DEADBEEF;
46
    t.guardbeef2 = DEADBEEF;
47
    t.prevbeef = prevbeef;
48

    
49
    /* eat stack space */
50
    d = dist( p, &t );
51
    if( d < size )
52
    {
53
        eat( p, size, &t );
54
    }
55

    
56
    /* make t a free block and link into task list */
57
    t.size = p->size - d;                 // set sizes
58
    p->size = d;
59
    t.used = false;
60
    t.next = p->next;                     // insert into list after p
61
    p->next = &t;
62

    
63
    /* free block made -- return to caller (task_init() or for(;;) loop below) */
64
    /* next longjmp to us will be from task_create() */
65
    if( SETJMP( t.jmpb ) == 0 )           // save state
66
    {
67
        memcpy(t.rst_jmpb, t.jmpb, sizeof(jmp_buf)); // save this state
68
        LONGJMP( p->jmpb, 1 );            // return to caller
69
    }
70

    
71
    /* setup task --> run task --> free block sequence */
72
    for( ;; )
73
    {
74
        /* we get here from task_create() */
75
        /*  it has put required stack size into t.stack_size */
76
        if( t.stack_size + MIN_STACKSIZE <= t.size )    // too big for us?
77
        {
78
            if( SETJMP( t.jmpb ) == 0 )    // split block to free unused space
79
            {
80
              eat( &t, t.stack_size, NULL ); // make free block
81
            }
82
        }
83
        t.used = true;                     // mark as used
84

    
85
        /* wait for next longjmp to us (that'll be to run task) */
86
        if( SETJMP( t.jmpb ) == 0 )        // wait
87
        {
88
            LONGJMP( tmp_jmpb, 1 );        // return to task_create()
89
        }
90

    
91
        /* run task */
92
        (*t.fnp)( t.arg );
93

    
94
        /* task finished -- free this block */
95
        task_free( &t );
96

    
97
        /* job done -- switch to main task */
98
        if( SETJMP( t.jmpb ) == 0 )         // save state
99
        {
100
            task_switchto( &main_task );
101
        }
102
    }
103
}
104

    
105
void task_init( unsigned total_stack, unsigned main_stack )
106
{
107
    _Task tmp;
108

    
109
    tmp.size = total_stack;               // initialize total stack area
110
    tmp.next = NULL;
111
    if( SETJMP( tmp.jmpb ) == 0 )
112
    {
113
      eat( &tmp, main_stack, NULL );      // reserve main stack and create
114
                                          //   first free task block
115
    }
116
    main_task = tmp;                      // copy to global variable
117
    main_task.used = true;
118
    current_task = &main_task;
119
}
120

    
121
_Task *task_create( _Task_fn fnp, void *arg, unsigned stack_size )
122
{
123
    _Task *p;
124

    
125
    for( p = main_task.next; p != NULL; p = p->next )     // find free block
126
    {
127
        if( !p->used && p->size >= stack_size )
128
        {
129
            p->fnp = fnp;                     // set task parameters
130
            p->arg = arg;
131
            p->stack_size = stack_size;
132
            if( SETJMP( tmp_jmpb ) == 0 )     // activate control block
133
            {
134
                LONGJMP( p->rst_jmpb, 1 );
135
            }
136
            return p;
137
        }
138
    }
139
    return NULL;                      // not enough stack
140
}
141

    
142

    
143
void task_switchto( _Task *p )
144
{
145
    if( SETJMP( current_task->jmpb ) == 0  )  // save state
146
    {
147
        current_task = p;
148
        LONGJMP( p->jmpb, 1 );              // run next task
149
    }
150
}
151

    
152

    
153
void task_free( _Task *t )
154
{
155
    t->used = false;                     // mark as free
156
    if( t->next != NULL && !t->next->used )
157
    {
158
        t->size += t->next->size;        // merge with following block
159
        t->next = t->next->next;
160
    }
161

    
162
    _Task *p = main_task.next;           // loop through list
163
    if( p != t )                         // if not first block
164
    {
165
        while( p->next != t )            // locate previous block
166
        {
167
            p = p->next;
168
        }
169
        if( !p->used )                   // if free
170
        {
171
            p->size += t->size;          // then merge
172
            p->next = t->next;
173
        }
174
    }
175
}
176

    
177
void task_restart( _Task *p )
178
{
179
    if( SETJMP( tmp_jmpb ) == 0 )        // activate control block
180
    {
181
       LONGJMP( p->rst_jmpb, 1 );
182
    }
183
}
184

    
185
bool task_testoverflow( _Task *t )
186
{
187
    if (!t->used || !t->next)
188
       return false;
189
    return t->next->guardbeef1!=DEADBEEF || t->next->guardbeef2!=DEADBEEF;
190
}
191

    
192
unsigned task_stackusage( _Task *t )
193
{
194
    if (!t->used)
195
       return 0;
196
    if (!t->next)                        // if unable to test
197
       return t->stack_size;             // then return requested size
198

    
199
    _Task *p = t->next;
200
    if (p->guardbeef1!=DEADBEEF ||       // if overflow
201
        p->guardbeef2!=DEADBEEF ||
202
        (p->prevbeef!=NULL && dist(p,p->prevbeef) > EATFRAME_MAX))
203
       return t->size;                   // then return actual size
204

    
205
    /* walk backwards -- if the beef are still there, that area is untouched */
206
    while (p->prevbeef!=NULL &&
207
           p->prevbeef->guardbeef1==DEADBEEF &&
208
           p->prevbeef->guardbeef2==DEADBEEF &&
209
           dist(p->prevbeef,p->prevbeef->prevbeef) <= EATFRAME_MAX)
210
       p = p->prevbeef;
211

    
212
    return dist(t,p);
213
}
214

    
215
NAMESPACE_END
216