File: coroutine_ext.cpp

package info (click to toggle)
falconpl 0.9.6.9-git20120606-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 46,176 kB
  • sloc: cpp: 181,389; ansic: 109,025; yacc: 2,310; xml: 1,218; sh: 403; objc: 245; makefile: 82; sql: 20
file content (280 lines) | stat: -rw-r--r-- 9,583 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*
   FALCON - The Falcon Programming Language.
   FILE: coroutine_ext.cpp

   Coroutine support, sleep functions, kind request functions.
   -------------------------------------------------------------------
   Author: Giancarlo Niccolai
   Begin: Thu, 14 Aug 2008 00:17:31 +0200

   -------------------------------------------------------------------
   (C) Copyright 2008: the FALCON developers (see list in AUTHORS file)

   See LICENSE file for licensing details.
*/

#include "core_module.h"
#include "../vmsema.h"
#include <falcon/falconobject.h>

/*#
   @beginmodule core
*/

namespace Falcon {
namespace core {

/*#
   @group coro_sup Coroutine support

   The functions in this group allows to interact with the coroutine support that is
   provided by the Virtual Machine. Most of them translate in requests to the virtual
   machine.

   Also, functions in this group are meant to permeate the embedding applications.
   Requests generate by coroutining are delivered to the application for approval
   and control.

   @begingroup coro_sup
*/

/*#
   @function yield
   @ingroup coroutine_support
   @brief gives up the rest of the coroutine time slice.

   This signals the VM that the current coroutine is temporarily done, and that another
   coroutine may be executed. If no other coroutines can be executed, current coroutine
   is resumed immediately (actually, it is never swapped out).
*/
FALCON_FUNC  yield ( ::Falcon::VMachine *vm )
{
   vm->rotateContext();
}

/*#
   @function yieldOut
   @brief Terminates current coroutine.
   @ingroup coroutine_support
   @param retval a return value for the coroutine.

   The current coroutine is terminated. If this is the last coroutine,
   the VM exits. Calling this function has the same effect of the END
   virtual machine PCODE.

   In multithreading context, exiting from the last coroutine causes
   a clean termination of the current thread.

   @see exit
*/
FALCON_FUNC  yieldOut ( ::Falcon::VMachine *vm )
{
   Item *ret = vm->param(0);
   
   if ( ret != 0 )
      vm->retval( *ret );
   else
      vm->retnil();

   vm->terminateCurrentContext();
}


/*#
   @function sleep
   @brief Put the current coroutine at sleep for some time.
   @param time Time, in seconds and fractions, that the coroutine wishes to sleep.
   @return an item posted by the embedding application.
   @ingroup coroutine_support
   @raise InterruptedError in case of asynchronous interruption.

   This function declares that the current coroutines is not willing to proceed at
   least for the given time. The VM will swap out the coroutine until the time has
   elapsed, and will make it eligible to run again after the given time lapse.

   The parameter may be a floating point number if a pause shorter than a second is
   required.

   The @b sleep() function can be called also when the VM has not started any coroutine;
   this will make it to be idle for the required time.

   In embedding applications, the Virtual Machine can be instructed to detect needed idle
   time and return to the calling application instead of performing a system request to
   sleep. In this way, embedding applications can use the idle time of the virtual machine
   to perform background operations. Single threaded applications may continue their execution
   and schedule continuation of the Virtual Machine at a later time, and multi-threaded
   applications can perform background message processing.

   This function complies with the interrupt protocol. The Virtual Machine may be
   asynchronously interrupted from the outside (i.e. from another thread). In this case,
   @b sleep will immediately raise an @a InterruptedError instance. The script may just
   ignore this exception and let the VM to terminate immediately, or it may honor the
   request after a cleanup it provides in a @b catch block, or it may simply ignore the
   request and continue the execution by discarding the error through an appropriate
   @b catch block.

   @see interrupt_protocol
*/

FALCON_FUNC  _f_sleep ( ::Falcon::VMachine *vm )
{
   Item *amount = vm->param(0);
   numeric pause;
   if( amount == 0 )
      pause = 0.0;
   else {
      pause = amount->forceNumeric();
      if ( pause < 0.0 )
         pause = 0.0;
   }

   vm->yield( pause );
}

/*#
   @function beginCritical
   @brief Signals the VM that this coroutine must not be interrupted.
   @ingroup coroutine_support

   After this call the VM will abstain from swapping this coroutine out
   of the execution context. The coroutine can then alter a set of data that
   must be prepare and readied for other coroutines, and then call @a endCritical
   or @a yield to pass the control back to the other coroutines.

   This function is not recursive. Successive calls to @b beginCritical are not
   counted, and have actually no effect. The first call to @a yield will swap
   out the coroutine, and the first call to @a endCritical will signal the
   availability of the routine to be swapped out, no matter how many
   times @a beginCritical has been called.
*/

FALCON_FUNC  beginCritical ( ::Falcon::VMachine *vm )
{
   vm->allowYield( false );
}

/*#
   @function endCritical
   @brief Signals the VM that this coroutine can be interrupted.
   @ingroup coroutine_support

   After this call, the coroutine may be swapped. This will happen
   only if/when the timeslice for this coroutine is over.

   This function is not recursive. Successive calls to @a beginCritical
   are not counted, and have actually no effect.
   The first call to @a yield will swap out the coroutine, and the first
   call to @a endCritical will signal the availability of the routine to be
   swapped out, no matter how many times @a beginCritical has been called.
*/

FALCON_FUNC  endCritical ( ::Falcon::VMachine *vm )
{
   vm->allowYield( true );
}

/*#
   @class Semaphore
   @brief Simple coroutine synchronization device.
   @ingroup coroutine_support
   @optparam initValue Initial value for the semaphore; if not given, 0 will be assumed.

   The semaphore is a simple synchronization object that is used by coroutines to
   communicate each others about relevant changes in the status of the application.

   Decrements the value of the semaphore, and eventually waits for the value to be > 0.
   When a @a Semaphore.wait method is called on a semaphore, two things may happen:
   if the value of the semaphore is greater than zero, the value is decremented and the
   coroutine can proceed. If it's zero, the coroutine is swapped out until the
   semaphore gets greater than zero again. When this happens, the coroutine
   decrements the value of the semaphore and proceeds. If a timeout parameter is given,
   in case the semaphore wasn't posted before the given timeout the function will return
   false.

   The order by which coroutines are resumed is the same by which they asked
   to wait on a semaphore. In this sense, @a Semaphore.wait method is implemented as a fair
   wait routine.

   The @a Semaphore.post method will raise the count of the semaphore by the given parameter
   (1 is the default if the parameter is not given). However, the calling coroutine
   won't necessarily be swapped out until a @a yield is called.

   By default, the semaphore is initialized to zero; this means that the
   first wait will block the waiting coroutine, unless a @a Semaphore.post
   is issued first.
*/
FALCON_FUNC  Semaphore_init ( ::Falcon::VMachine *vm )
{
   Item *qty = vm->param(0);
   int32 value = 0;
   if ( qty != 0 ) {
      if ( qty->type() == FLC_ITEM_INT )
         value = (int32) qty->asInteger();
      else if ( qty->type() == FLC_ITEM_NUM )
         value = (int32) qty->asNumeric();
      else {
         throw new ParamError( ErrorParam( e_param_range ).extra( "( N )" ) );
      }
   }

   VMSemaphore *sem = new VMSemaphore( value );
   vm->self().asObject()->setUserData( sem );
}

/*#
   @method post Semaphore
   @brief Increments the count of the semaphore.
   @optparam count The amount by which the semaphore will be incremented (1 by default).

   This method will increment the count of the semaphore by 1 or by a specified amount,
   allowing the same number of waiting coroutines to proceed.

   However, the calling coroutine won't necessarily be swapped out until a @a yield is called.
*/
FALCON_FUNC  Semaphore_post ( ::Falcon::VMachine *vm )
{
   VMSemaphore *semaphore = dyncast< VMSemaphore *>(vm->self().asObject()->getFalconData());
   Item *qty = vm->param(0);
   int32 value = 1;
   if ( qty != 0 ) {
      if ( qty->type() == FLC_ITEM_INT )
         value = (int32)qty->asInteger();
      else if ( qty->type() == FLC_ITEM_NUM )
         value = (int32) qty->asNumeric();
      else {
         throw new ParamError( ErrorParam( e_inv_params ).extra( "( N )" ) );
      }
      if (value <= 0)
         value = 1;
   }

   semaphore->post( vm, value );
}

/*#
   @method wait Semaphore
   @brief Waits on a semaphore.
   @optparam timeout Optional maximum wait in seconds.

   Decrements the value of the semaphore, and eventually waits for the value to be greater
   than zero.
*/
FALCON_FUNC  Semaphore_wait ( ::Falcon::VMachine *vm )
{
   VMSemaphore *semaphore = dyncast< VMSemaphore *>(vm->self().asObject()->getFalconData());
   Item *i_wc = vm->param( 0 );
   if ( i_wc == 0 )
      semaphore->wait( vm );
   else {
      if ( ! i_wc->isOrdinal() )
      {
         throw new ParamError( ErrorParam( e_inv_params ).extra( "(N)" ) );
      }
      semaphore->wait( vm, i_wc->forceNumeric() );
   }
}

}
}

/* end of coroutine_ext.cpp */