1/*
2 * Copyright (C) 2001-2005 Chris Ross
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * o Redistributions of source code must retain the above copyright notice, this
9 *   list of conditions and the following disclaimer.
10 * o Redistributions in binary form must reproduce the above copyright notice,
11 *   this list of conditions and the following disclaimer in the documentation
12 *   and/or other materials provided with the distribution.
13 * o Neither the name of the ferite software nor the names of its contributors may
14 *   be used to endorse or promote products derived from this software without
15 *   specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30uses "thread.lib";
31
32module-header
33{
34
35#include "../../libs/aphex/include/aphex.h"
36
37#define SelfThread ((FeriteThread*)self->odata)
38#define SelfMutex  ((AphexMutex*)self->odata)
39#define SelfEvent  ((AphexEvent*)self->odata)
40
41    FeriteScript *ferite_thread_create_script( FeriteScript *script );
42    void ferite_thread_destroy_script( FeriteScript *script, FeriteThread *ctx, int fd );
43    void *ferite_thread_execute( void *ptr );
44
45}
46
47/**
48 * @class Thread
49 * @brief A thread object allowing for multi-threaded scripts within the ferite environment
50 * @description This class provides the basic framework for threading. To create a thread you
51                have to inherit from this base class and create a run method. Once that is done
52 *              You create an instance of the object and call the .start() method NOT the .run()
53 *              method. This causes a thread to be spawned and the .run() method called. The
54 *              thread will exit when the .run() method has completed. If you implement your
55 *              own constructor is is VITAL that you call super() to make sure that the
56 *              native side of the thread is instantiated correctly.
57 * @example <code>
58 <keyword>class</keyword> MyThread <keyword>extends</span> Thread {<nl/>
59 <tab/><keyword>function</keyword> run() {<nl/>
60 <tab/><tab/><keyword>while</keyword>( <type>true</type> ) {<nl/>
61 <tab/><tab/><tab/>Thread.sleep( 1000 ); <nl/>
62 <tab/><tab/><tab/>Console.println( "A<keyword>not</keyword>her Second Gone" );<nl/>
63 <tab/><tab/>}<nl/>
64 <tab/>}<tab/><nl/>
65 }<nl/>
66 <nl/>
67 <type>object</type> thread = <keyword>new</keyword> MyThread();<nl/>
68 thread.start( <keyword>true</keyword> );</code><nl/>
69 */
70class Thread
71{
72   /**
73    * @function constructor
74    * @declaration function constructor()
75    * @brief The constructor
76    * @warning You must make sure this is called within sub-classes.
77    */
78   native function constructor()
79   {
80       /* create new script for this thread */
81       self->odata = fmalloc( sizeof(FeriteThread) );
82       SelfThread->ctxt = aphex_thread_create();
83       SelfThread->script = ferite_thread_create_script( script );
84       SelfThread->obj = self;
85       SelfThread->running = FE_FALSE;
86       SelfThread->pass_exceptions = FE_FALSE;
87   }
88
89   native function destructor()
90   {
91       if( SelfThread != NULL )
92       {
93           if( !SelfThread->running )
94               ferite_thread_destroy_script( script, SelfThread, FE_TRUE );
95            self->odata = NULL;
96       }
97   }
98
99   /**
100    * @function start
101    * @declaration function start( number detach )
102    * @brief Start the thread of execution
103    * @param number detach 'true' or 'false', if 'true' the thread will detach upon running
104    * @description When this function is run, it will return straight away. Pass true if you want the
105    *              Thread to automatically clear itself up. Otherwise Thread.join() must be called on
106    *              it.
107    */
108   native function start( number detach )
109   {
110       if( SelfThread != NULL )
111       {
112           if( aphex_thread_start( SelfThread->ctxt, ferite_thread_execute, SelfThread, (int)detach ) != 0 )
113       	       ferite_error( script, 0, "Unable to start thread! Not enough resources!\n" );
114       }
115       else {
116         ferite_error( script, 0, "Unable to start thread! (this usually happens when the Thread constructor has not been called from the subclass.)\n" );
117       }
118   }
119
120    /**
121    * @function start
122     * @declaration function start()
123     * @brief Start the thread of execution
124     * @description When this function is run, it will return straight away. The thread will clean itself
125                    up when done.
126     */
127    function start()
128   {
129        return .start( true );
130   }
131
132   /**
133    * @function run
134    * @declaration function run()
135    * @brief The function that gets run. The stock run method exits immediatly. You need to implement your own function.
136    */
137   native function run();
138
139   /**
140    * @function sleep
141    * @declaration function sleep( number msecs )
142    * @brief Causes the thread to sleep for an amount of time
143    * @param number msecs The amount of time to sleep in microseconds
144    */
145   native function sleep( number msecs )
146   {
147       aphex_thread_sleep( SelfThread->ctxt, (long)msecs );
148   }
149
150   /**
151    * @function join
152    * @declaration static native function join( object thread )
153    * @brief Cause the calling thread to wait for the thread passed to the method to complete
154    * @param object thread The thread to wait for
155    * @static
156    * @example <nl/><code>
157    <keyword>class</keyword> MyThread <keyword>extends</span> Thread {<nl/>
158        <tab/><keyword>function</keyword> run() {<nl/>
159            <tab/><tab/><keyword>while</keyword>( <type>true</type> ) {<nl/>
160                <tab/><tab/><tab/>Thread.sleep( 1000 ); <nl/>
161                    <tab/><tab/><tab/>Console.println( "A<keyword>not</keyword>her Second Gone" );<nl/>
162                        <tab/><tab/>}<nl/>
163            <tab/>}<tab/><nl/>
164    }<nl/>
165    <nl/>
166    <type>object</type> thread = <keyword>new</keyword> MyThread();<nl/>
167    thread.start(<type>false</type>);<nl/>
168    Thread.join(thread); </code><nl/>
169    */
170   static native function join( object thread )
171   {
172       if( thread != NULL && thread->odata != NULL )
173       {
174           aphex_thread_join( ((FeriteThread*)thread->odata)->ctxt );
175       }
176   }
177
178   /**
179    * @function setPassExceptions
180    * @declaration function setPassExceptions( number value )
181    * @brief Set whether or not exceptions within a thread are passed onto the main process when the thread finishes executing.
182    * @param number value Either true or false
183    * @description If an exception is thrown within a thread, only that thread will suffer the exception. If you pass
184                   true to the function, when a thread has an exception it will pass it onto the main program thread.
185    */
186   native function setPassExceptions( number value )
187   {
188       SelfThread->pass_exceptions = (long)value;
189   }
190
191   /**
192    * @function isRunning
193    * @declaration function isRunning()
194    * @brief Check to see if the thread is running
195    * @return true if it is running, false otherwise
196    */
197   native function isRunning()
198   {
199       if( SelfThread->running )
200       {
201	   FE_RETURN_TRUE;
202       }
203       FE_RETURN_FALSE;
204   }
205}
206/**
207 * @end
208 */
209
210/**
211 * @class Mutex
212 * @brief A mutex that can be used to lock sections of code
213 * @example <code>
214 <type>object</type> mutex = <keyword>new</keyword> Mutex();<nl/>
215 mutex.lock();<nl/>
216 // Critical section<nl/>
217 mutex.unlock();</code><nl/>
218 */
219final class Mutex
220{
221   native function constructor()
222   {
223       if( SelfMutex != NULL )
224         self->odata = aphex_mutex_create();
225   }
226
227   native function destructor()
228   {
229       if( SelfMutex != NULL )
230         aphex_mutex_destroy( SelfMutex );
231       self->odata = NULL;
232   }
233
234   /**
235    * @function lock
236    * @declaration function lock()
237    * @brief Cause the mutex to lock
238    * @description The mutex will lock. If it is already locked, the thread of execution will stop until
239    *              it becomes unlocked.
240    */
241   native function lock()
242   {
243       if( SelfMutex != NULL )
244         aphex_mutex_lock( SelfMutex );
245   }
246
247   /**
248    * @function unlock
249    * @declaration function unlock()
250    * @brief Cause the mutex to unlock
251    */
252   native function unlock()
253   {
254       if( SelfMutex != NULL )
255         aphex_mutex_unlock( SelfMutex );
256   }
257}
258/**
259 * @end
260 */
261
262/**
263 * @class Event
264 * @brief A thread safe way of signalling events between threads
265 * @example <code>
266 <keyword>global</keyword> {<nl/>
267     <tab/><type>object</type> event;<nl/>
268         <tab/><type>number</type> value;<nl/>
269 }<nl/>
270 <nl/>
271 <keyword>class</keyword> Producer <keyword>extends</span> Thread {<nl/>
272     <tab/><keyword>function</keyword> run() {<nl/>
273         <tab/><tab/><keyword>while</keyword>( <type>true</type> ) {<tab/><tab/><tab/><nl/>
274             <tab/><tab/><tab/>value = 10;<nl/>
275                 <tab/><tab/><tab/>event.signal();<nl/>
276                     <tab/><tab/>}<nl/>
277         <tab/>}<nl/>
278 }<nl/>
279 <keyword>class</keyword> Consumer <keyword>extends</span> Thread {<nl/>
280     <tab/><keyword>function</keyword> run() {<nl/>
281         <tab/><tab/><keyword>while</keyword>( <type>true</type> ) {<nl/>
282             <tab/><tab/><tab/>event.wait();<nl/>
283                 <tab/><tab/><tab/>Console.println( "value: $value" );<nl/>
284                     <tab/><tab/>}<nl/>
285         <tab/>}<nl/>
286 }<nl/>
287 <nl/>
288 <type>object</type> producer = <keyword>new</keyword> Producer();<nl/>
289 <type>object</type> consumer = <keyword>new</keyword> Consumer();<nl/>
290 event = <keyword>new</keyword> Event();<nl/>
291 <nl/>
292 producer.start();<nl/>
293 consumer.start();</code><nl/>
294 */
295class Event
296{
297   native function constructor()
298   {
299       self->odata = aphex_event_create();
300   }
301
302   native function destructor()
303   {
304       if( SelfEvent != NULL )
305         aphex_event_destroy( SelfEvent );
306       self->odata = NULL;
307   }
308
309   /**
310    * @function signal
311    * @declaration function signal()
312    * @brief Cause an event to be broadcasted
313    * @description Signals any threads in wait or timedwait that it is okay to continue
314    *
315    */
316   native function signal()
317   {
318       if( SelfEvent != NULL )
319         aphex_event_signal( SelfEvent );
320   }
321
322   /**
323    * @function wait
324    * @declaration function wait()
325    * @brief This thread will wait for a signal to be called
326    */
327   native function wait()
328   {
329       if( SelfEvent != NULL )
330         aphex_event_wait( SelfEvent );
331   }
332
333   /**
334    * @function timedWait
335    * @declaration function timedWait( number seconds)
336    * @brief This thread will wait for a signal to be called
337    * @param number seconds The amount of time to wait in seconds
338    * @return true if a signal was caught, false otherwise
339    */
340   native function timedWait( number seconds )
341   {
342       if( SelfEvent != NULL )
343       {
344           if( aphex_event_timedwait( SelfEvent, (long)seconds) == 0)
345           {
346               FE_RETURN_TRUE;
347           }
348       }
349       FE_RETURN_FALSE;
350   }
351}
352/**
353 * @end
354 */
355
356