PageRenderTime 392ms CodeModel.GetById 171ms app.highlight 19ms RepoModel.GetById 152ms app.codeStats 0ms

/thread/UserThread.cpp

http://github.com/dennis-gemini/tests
C++ | 199 lines | 167 code | 30 blank | 2 comment | 28 complexity | 26189a3d493f4d4ad8b08066a003bae2 MD5 | raw file
  1#include <ucontext.h>
  2#include <stdio.h>
  3#include <stdlib.h>
  4#include <errno.h>
  5#include <error.h>
  6#include <string.h>
  7
  8#define DEFAULT_STACK_SIZE      (10 * 1024)
  9#define ERROR(msg...)           error_at_line(-1, errno, __FILE__, __LINE__, ##msg)
 10
 11class UserThread
 12{
 13public:
 14        static void
 15        schedule()
 16        {
 17                if(getcontext(&scheduler) == -1) {
 18                        ERROR("getcontext");
 19                }
 20
 21                if(current == NULL) {
 22                        current = head;
 23                } else {
 24                        current = current->next;
 25                }
 26
 27                if(current) {
 28                        printf("switching to %s\n", current->getName());
 29
 30                        if(setcontext(&current->context) == -1) {
 31                                ERROR("setcontext");
 32                        }
 33                } else {
 34                        printf("no current thread, exiting scheduler loop...\n");
 35                }
 36        }
 37
 38protected:
 39        UserThread(size_t stackSize = DEFAULT_STACK_SIZE):
 40                prev(NULL), next(NULL)
 41        {
 42                stackBase = (unsigned char*) calloc(stackSize, 1);
 43
 44                if(stackBase == NULL) {
 45                        ERROR("calloc");
 46                }
 47                this->stackSize = stackSize;
 48
 49                link();
 50        }
 51
 52        virtual
 53        ~UserThread()
 54        {
 55                free(stackBase);
 56        }
 57
 58        virtual void
 59        run()
 60        {
 61        }
 62
 63        virtual const char*
 64        getName() const
 65        {	return "<noname>";
 66        }
 67
 68        void
 69        idle()
 70        {
 71                if(swapcontext(&context, &scheduler) == -1) {
 72                        ERROR("swapcontext");
 73                }
 74        }
 75
 76private:
 77        static void
 78        threadRoutine(UserThread* self)
 79        {
 80                if(self) {
 81                        self->run();
 82                        self->unlink();
 83                }
 84        }
 85
 86        void
 87        link()
 88        {
 89                if(head) {
 90                        this->prev = head->prev;
 91                        this->next = head;
 92
 93                        this->prev->next = this;
 94                        this->next->prev = this;
 95                } else {
 96                        this->prev = this;
 97                        this->next = this;
 98                }
 99                head = this;
100
101                if(getcontext(&context) == -1) {
102                        ERROR("getcontext");
103                }
104                context.uc_stack.ss_sp   = stackBase;
105                context.uc_stack.ss_size = stackSize;
106                context.uc_link          = &scheduler;
107                makecontext(&context, (void(*)()) &threadRoutine, 1, this);
108        }
109
110        void
111        unlink()
112        {
113                if(prev && next) {
114                        if(prev == this) {
115                                head    = NULL;
116                                current =  NULL;
117                        } else {
118                                prev->next = next;
119                                next->prev = prev;
120
121                                if(head == this) {
122                                        head = next;
123                                }
124                                if(current == this) {
125                                        current = prev;
126                                }
127                        }
128                }
129        }
130
131        static UserThread* head;
132        static UserThread* current;
133        static ucontext_t  scheduler;
134
135        UserThread*        prev;
136        UserThread*        next;
137        ucontext_t         context;
138        size_t             stackSize;
139        unsigned char*     stackBase;
140};
141
142UserThread* UserThread::head    = NULL;
143UserThread* UserThread::current = NULL;
144ucontext_t  UserThread::scheduler;
145
146///////////////////////////////////////////////////////////////////
147
148class Worker: public UserThread
149{
150        int   num;
151        int   cur;
152	char* name;
153public:
154        Worker(int num): num(num), cur(-1)
155        {
156		char buf[256];
157		snprintf(buf, sizeof(buf), "Worker[%d]", num);
158		name = strdup(buf);
159        }
160
161        virtual
162        ~Worker()
163        {
164		free(name);
165        }
166
167protected:
168        virtual void
169        run()
170        {
171                for(cur = 0; cur < 5; cur++) {
172                        printf("Worker[%d]: %d\n", num, cur);
173                        idle();
174                }
175                printf("Worker[%d]: exited.\n", num);
176        }
177
178        virtual const char*
179        getName() const
180        {
181                return name;
182        }
183};
184
185int
186main(int argc, char** argv)
187{
188        Worker worker1(1);
189        Worker worker2(2);
190        Worker worker3(3);
191        Worker worker4(4);
192        Worker worker5(5);
193
194        UserThread::schedule();
195        return 0;
196}
197
198/* vim:set ts=8 sw=8 foldmethod=syntax foldlevel=1 nu: */
199