ecere/net: Socket & Distributed Objects tweaks to work around various issues (Blokus)
[sdk] / ecere / src / sys / Thread.ec
1 namespace sys;
2
3 #define uint _uint
4 // Platform includes
5 #if defined(__WIN32__)
6 #define WIN32_LEAN_AND_MEAN
7 #include <windows.h>
8 #else
9 #include <pthread.h>
10 #include <sys/signal.h>
11 #endif
12 #undef uint
13
14 import "instance"
15
16 #if !defined(__WIN32__)
17 import "Semaphore"
18 #endif
19
20 public enum ThreadPriority
21 {
22    normal = 0,
23    aboveNormal = 1,
24    belowNormal = -1,
25    highest = 2,
26    lowest = -2,
27    idle = -15,
28    timeCritical = 15
29 };
30
31 public int GetCurrentThreadID()
32 {
33 #if defined(__WIN32__)
34    return (int)GetCurrentThreadId();
35 #else
36    return pthread_self();
37 #endif
38 }
39
40 public class Thread
41 {
42    ~Thread()
43    {
44 #if defined(__WIN32__)
45       if(handle) 
46          CloseHandle(handle);
47 #endif
48    }
49
50 #if defined(__WIN32__)
51    HANDLE handle;
52    uint id;
53 #else
54    pthread_t id;
55    bool dontDetach;
56    Semaphore sem { };
57 #endif
58
59    uint returnCode;
60    bool started;
61
62    uint ThreadCallBack()
63    {
64       uint returnCode = this.returnCode = Main();
65       started = false;
66 #if defined(__WIN32__)
67       CloseHandle(handle);
68       handle = null;
69 #else
70       if(!dontDetach)
71          pthread_detach(id);
72       sem.Release();
73
74 #endif
75       delete this;
76       return returnCode;
77    }
78
79 public:
80    virtual uint Main(void);
81
82    void Create()
83    {
84       incref this;
85       if(!started)
86       {
87 #if !defined(__WIN32__)
88          sem.TryWait();
89 #endif
90          started = true;
91          // printf("Creating %s thread\n", _class.name);
92 #if defined(__WIN32__)
93          if(!handle)
94             handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadCallBack, this, 0, &id);
95 #else
96          {
97             int error;
98             /*pthread_attr_t attr;
99             pthread_attr_init(&attr);
100             pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);*/  // Default attribute ???
101             error = pthread_create(&id, null /*&attr*/, (void *)ThreadCallBack, this);
102             if(error)
103                printf("Error %d creating a thread\n", error);
104           }
105 #endif
106       }
107    }
108
109    void Kill()
110    {
111 #if defined(__WIN32__)
112       if(handle)
113       {
114          TerminateThread(handle, 0);
115          handle = null;
116       }
117 #else
118       if(started) 
119          pthread_kill(id, SIGQUIT);
120 #endif
121       if(started)
122       {
123          started = false;
124          delete this;
125       }
126    }
127
128    void Wait()
129    {
130 #if defined(__WIN32__)
131       if(WaitForSingleObject(handle, INFINITE /*2000*/) == WAIT_TIMEOUT)
132          PrintLn("Thread not returning?\n");
133 #else
134       
135       /*dontDetach = true;
136       if(started)
137          pthread_join(id, NULL);*/
138
139       if(started)
140          sem.Wait();
141 #endif
142    }
143
144    void SetPriority(ThreadPriority priority)
145    {
146 #if defined(__WIN32__)
147       SetThreadPriority(handle, priority);
148 #else
149       /*
150       struct sched_param param;
151       int policy = (priority > 0) ? SCHED_RR : SCHED_OTHER;
152       param.sched_priority = (priority > 0) ? (priority * 99 / 15) : 0;
153       pthread_setschedparam(id, policy, &param);
154       */
155 #endif      
156    }
157
158    property bool created { get { return started; } };
159 }