1 /* Jim - A small embeddable Tcl interpreter
3 * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
4 * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
5 * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
6 * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
7 * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
8 * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
9 * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
24 * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
25 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
26 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 * The views and conclusions contained in the software and documentation
38 * are those of the authors and should not be interpreted as representing
39 * official policies, either expressed or implied, of the Jim Tcl Project.
43 * - to really use flags in Jim_ProcessEvents()
44 * - more complete [after] command with [after info] and other subcommands.
52 #define __JIM_EVENTLOOP_CORE__
54 #include <pkgconf/jimtcl.h>
57 #include <cyg/jimtcl/jim.h>
58 #include <cyg/jimtcl/jim-eventloop.h>
61 #include "jim-eventloop.h"
66 #include <sys/types.h>
71 #include "replacements.h"
76 /* File event structure */
77 typedef struct Jim_FileEvent
{
79 int mask
; /* one of JIM_EVENT_(READABLE|WRITABLE|EXCEPTION) */
80 Jim_FileProc
*fileProc
;
81 Jim_EventFinalizerProc
*finalizerProc
;
83 struct Jim_FileEvent
*next
;
86 /* Time event structure */
87 typedef struct Jim_TimeEvent
{
88 jim_wide id
; /* time event identifier. */
89 int mode
; /* restart, repetitive .. UK */
90 long initialms
; /* initial relativ timer value UK */
91 long when_sec
; /* seconds */
92 long when_ms
; /* milliseconds */
93 Jim_TimeProc
*timeProc
;
94 Jim_EventFinalizerProc
*finalizerProc
;
96 struct Jim_TimeEvent
*next
;
99 /* Per-interp stucture containing the state of the event loop */
100 typedef struct Jim_EventLoop
{
101 jim_wide timeEventNextId
;
102 Jim_FileEvent
*fileEventHead
;
103 Jim_TimeEvent
*timeEventHead
;
106 void Jim_CreateFileHandler(Jim_Interp
*interp
, void *handle
, int mask
,
107 Jim_FileProc
*proc
, void *clientData
,
108 Jim_EventFinalizerProc
*finalizerProc
)
111 Jim_EventLoop
*eventLoop
= Jim_GetAssocData(interp
, "eventloop");
113 // fprintf(stderr,"rein\n");
114 fe
= Jim_Alloc(sizeof(*fe
));
118 fe
->finalizerProc
= finalizerProc
;
119 fe
->clientData
= clientData
;
120 fe
->next
= eventLoop
->fileEventHead
;
121 eventLoop
->fileEventHead
= fe
;
122 // fprintf(stderr,"raus\n");
125 void Jim_DeleteFileHandler(Jim_Interp
*interp
, void *handle
)
127 Jim_FileEvent
*fe
, *prev
= NULL
;
128 Jim_EventLoop
*eventLoop
= Jim_GetAssocData(interp
, "eventloop");
130 fe
= eventLoop
->fileEventHead
;
132 if (fe
->handle
== handle
) {
134 eventLoop
->fileEventHead
= fe
->next
;
136 prev
->next
= fe
->next
;
137 if (fe
->finalizerProc
)
138 fe
->finalizerProc(interp
, fe
->clientData
);
147 // The same for signals.
148 void Jim_CreateSignalHandler(Jim_Interp
*interp
, int signum
,
149 Jim_FileProc
*proc
, void *clientData
,
150 Jim_EventFinalizerProc
*finalizerProc
)
153 void Jim_DeleteSignalHandler(Jim_Interp
*interp
, int signum
)
157 /* That's another part of this extension that needs to be ported
159 static void JimGetTime(long *seconds
, long *milliseconds
)
163 gettimeofday(&tv
, NULL
);
164 *seconds
= tv
.tv_sec
;
165 *milliseconds
= tv
.tv_usec
/1000;
168 jim_wide
Jim_CreateTimeHandler(Jim_Interp
*interp
, jim_wide milliseconds
,
169 Jim_TimeProc
*proc
, void *clientData
,
170 Jim_EventFinalizerProc
*finalizerProc
)
172 Jim_EventLoop
*eventLoop
= Jim_GetAssocData(interp
, "eventloop");
173 jim_wide id
= eventLoop
->timeEventNextId
++;
175 long cur_sec
, cur_ms
;
177 JimGetTime(&cur_sec
, &cur_ms
);
179 te
= Jim_Alloc(sizeof(*te
));
182 te
->initialms
= milliseconds
;
183 te
->when_sec
= cur_sec
+ milliseconds
/1000;
184 te
->when_ms
= cur_ms
+ milliseconds
%1000;
185 if (te
->when_ms
>= 1000) {
190 te
->finalizerProc
= finalizerProc
;
191 te
->clientData
= clientData
;
192 te
->next
= eventLoop
->timeEventHead
;
193 eventLoop
->timeEventHead
= te
;
197 jim_wide
Jim_DeleteTimeHandler(Jim_Interp
*interp
, jim_wide id
)
199 Jim_TimeEvent
*te
, *prev
= NULL
;
200 Jim_EventLoop
*eventLoop
= Jim_GetAssocData(interp
, "eventloop");
201 long cur_sec
, cur_ms
;
204 JimGetTime(&cur_sec
, &cur_ms
);
206 te
= eventLoop
->timeEventHead
;
207 if (id
>= eventLoop
->timeEventNextId
)
208 return -2; /* wrong event ID */
211 remain
= (te
->when_sec
- cur_sec
) * 1000;
212 remain
+= (te
->when_ms
- cur_ms
) ;
213 remain
= (remain
< 0) ? 0 : remain
;
216 eventLoop
->timeEventHead
= te
->next
;
218 prev
->next
= te
->next
;
219 if (te
->finalizerProc
)
220 te
->finalizerProc(interp
, te
->clientData
);
227 return -1; /* NO event with the specified ID found */
230 /* Search the first timer to fire.
231 * This operation is useful to know how many time the select can be
232 * put in sleep without to delay any event.
233 * If there are no timers NULL is returned. */
234 static Jim_TimeEvent
*JimSearchNearestTimer(Jim_EventLoop
*eventLoop
)
236 Jim_TimeEvent
*te
= eventLoop
->timeEventHead
;
237 Jim_TimeEvent
*nearest
= NULL
;
240 if (!nearest
|| te
->when_sec
< nearest
->when_sec
||
241 (te
->when_sec
== nearest
->when_sec
&&
242 te
->when_ms
< nearest
->when_ms
))
249 /* --- POSIX version of Jim_ProcessEvents, for now the only available --- */
250 #define JIM_FILE_EVENTS 1
251 #define JIM_TIME_EVENTS 2
252 #define JIM_ALL_EVENTS (JIM_FILE_EVENTS|JIM_TIME_EVENTS)
253 #define JIM_DONT_WAIT 4
255 /* Process every pending time event, then every pending file event
256 * (that may be registered by time event callbacks just processed).
257 * Without special flags the function sleeps until some file event
258 * fires, or when the next time event occurrs (if any).
260 * If flags is 0, the function does nothing and returns.
261 * if flags has JIM_ALL_EVENTS set, all the kind of events are processed.
262 * if flags has JIM_FILE_EVENTS set, file events are processed.
263 * if flags has JIM_TIME_EVENTS set, time events are processed.
264 * if flags has JIM_DONT_WAIT set the function returns ASAP until all
265 * the events that's possible to process without to wait are processed.
267 * The function returns the number of events processed. */
268 int Jim_ProcessEvents(Jim_Interp
*interp
, int flags
)
270 int maxfd
= 0, numfd
= 0, processed
= 0;
271 fd_set rfds
, wfds
, efds
;
272 Jim_EventLoop
*eventLoop
= Jim_GetAssocData(interp
, "eventloop");
273 Jim_FileEvent
*fe
= eventLoop
->fileEventHead
;
282 /* Check file events */
284 int fd
= fileno((FILE*)fe
->handle
);
286 if (fe
->mask
& JIM_EVENT_READABLE
)
288 if (fe
->mask
& JIM_EVENT_WRITABLE
) FD_SET(fd
, &wfds
);
289 if (fe
->mask
& JIM_EVENT_EXCEPTION
) FD_SET(fd
, &efds
);
290 if (maxfd
< fd
) maxfd
= fd
;
294 /* Note that we want call select() even if there are no
295 * file events to process as long as we want to process time
296 * events, in order to sleep until the next time event is ready
298 if (numfd
|| ((flags
& JIM_TIME_EVENTS
) && !(flags
& JIM_DONT_WAIT
))) {
300 Jim_TimeEvent
*shortest
;
301 struct timeval tv
, *tvp
;
304 shortest
= JimSearchNearestTimer(eventLoop
);
306 long now_sec
, now_ms
;
308 /* Calculate the time missing for the nearest
310 JimGetTime(&now_sec
, &now_ms
);
312 dt
= 1000 * (shortest
->when_sec
- now_sec
);
313 dt
+= ( shortest
->when_ms
- now_ms
);
317 tvp
->tv_sec
= dt
/ 1000;
318 tvp
->tv_usec
= dt
% 1000;
319 // fprintf(stderr,"Next %d.% 8d\n",(int)tvp->tv_sec,(int)tvp->tv_usec);
321 tvp
= NULL
; /* wait forever */
322 // fprintf(stderr,"No Event\n");
325 retval
= select(maxfd
+1, &rfds
, &wfds
, &efds
, tvp
);
328 case EINTR
: fprintf(stderr
,"select EINTR\n"); break;
329 case EINVAL
: fprintf(stderr
,"select EINVAL\n"); break;
330 case ENOMEM
: fprintf(stderr
,"select ENOMEM\n"); break;
332 } else if (retval
> 0) {
333 fe
= eventLoop
->fileEventHead
;
335 int fd
= fileno((FILE*)fe
->handle
);
337 // fprintf(stderr,"fd: %d mask: %02x \n",fd,fe->mask);
339 if ((fe
->mask
& JIM_EVENT_READABLE
&& FD_ISSET(fd
, &rfds
)) ||
340 (fe
->mask
& JIM_EVENT_WRITABLE
&& FD_ISSET(fd
, &wfds
)) ||
341 (fe
->mask
& JIM_EVENT_EXCEPTION
&& FD_ISSET(fd
, &efds
)))
345 if (fe
->mask
& JIM_EVENT_READABLE
&& FD_ISSET(fd
, &rfds
)) {
346 mask
|= JIM_EVENT_READABLE
;
347 if ((fe
->mask
& JIM_EVENT_FEOF
) && feof((FILE *)fe
->handle
))
348 mask
|= JIM_EVENT_FEOF
;
350 if (fe
->mask
& JIM_EVENT_WRITABLE
&& FD_ISSET(fd
, &wfds
))
351 mask
|= JIM_EVENT_WRITABLE
;
352 if (fe
->mask
& JIM_EVENT_EXCEPTION
&& FD_ISSET(fd
, &efds
))
353 mask
|= JIM_EVENT_EXCEPTION
;
354 if (fe
->fileProc(interp
, fe
->clientData
, mask
) == JIM_ERR
) {
355 /* Remove the element on handler error */
356 Jim_DeleteFileHandler(interp
, fe
->handle
);
359 /* After an event is processed our file event list
360 * may no longer be the same, so what we do
361 * is to clear the bit for this file descriptor and
362 * restart again from the head. */
363 fe
= eventLoop
->fileEventHead
;
373 /* Check time events */
374 te
= eventLoop
->timeEventHead
;
375 maxId
= eventLoop
->timeEventNextId
-1;
377 long now_sec
, now_ms
;
380 if (te
->id
> maxId
) {
384 JimGetTime(&now_sec
, &now_ms
);
385 if (now_sec
> te
->when_sec
||
386 (now_sec
== te
->when_sec
&& now_ms
>= te
->when_ms
))
389 te
->timeProc(interp
, te
->clientData
);
390 /* After an event is processed our time event list may
391 * no longer be the same, so we restart from head.
392 * Still we make sure to don't process events registered
393 * by event handlers itself in order to don't loop forever
394 * even in case an [after 0] that continuously register
395 * itself. To do so we saved the max ID we want to handle. */
396 Jim_DeleteTimeHandler(interp
, id
);
397 te
= eventLoop
->timeEventHead
;
405 /* ---------------------------------------------------------------------- */
407 void JimELAssocDataDeleProc(Jim_Interp
*interp
, void *data
)
412 Jim_EventLoop
*eventLoop
= data
;
414 fe
= eventLoop
->fileEventHead
;
417 if (fe
->finalizerProc
)
418 fe
->finalizerProc(interp
, fe
->clientData
);
423 te
= eventLoop
->timeEventHead
;
426 if (te
->finalizerProc
)
427 te
->finalizerProc(interp
, te
->clientData
);
434 static int JimELVwaitCommand(Jim_Interp
*interp
, int argc
,
435 Jim_Obj
*const *argv
)
440 Jim_WrongNumArgs(interp
, 1, argv
, "name");
443 oldValue
= Jim_GetGlobalVariable(interp
, argv
[1], JIM_NONE
);
444 if (oldValue
) Jim_IncrRefCount(oldValue
);
448 Jim_ProcessEvents(interp
, JIM_ALL_EVENTS
);
449 currValue
= Jim_GetGlobalVariable(interp
, argv
[1], JIM_NONE
);
450 /* Stop the loop if the vwait-ed variable changed value,
451 * or if was unset and now is set (or the contrary). */
452 if ((oldValue
&& !currValue
) ||
453 (!oldValue
&& currValue
) ||
454 (oldValue
&& currValue
&&
455 !Jim_StringEqObj(oldValue
, currValue
, JIM_CASESENS
)))
458 if (oldValue
) Jim_DecrRefCount(interp
, oldValue
);
462 void JimAfterTimeHandler(Jim_Interp
*interp
, void *clientData
)
464 Jim_Obj
*objPtr
= clientData
;
466 Jim_EvalObjBackground(interp
, objPtr
);
469 void JimAfterTimeEventFinalizer(Jim_Interp
*interp
, void *clientData
)
471 Jim_Obj
*objPtr
= clientData
;
473 Jim_DecrRefCount(interp
, objPtr
);
476 static int JimELAfterCommand(Jim_Interp
*interp
, int argc
,
477 Jim_Obj
*const *argv
)
480 Jim_Obj
*objPtr
, *idObjPtr
;
481 const char *options
[] = {
482 "info", "cancel", "restart", "expire", NULL
484 enum {INFO
, CANCEL
, RESTART
, EXPIRE
, CREATE
};
485 int option
= CREATE
;
488 Jim_WrongNumArgs(interp
, 1, argv
, "<after milliseconds> script");
491 if (Jim_GetWide(interp
, argv
[1], &ms
) != JIM_OK
)
492 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, "after options",
493 JIM_ERRMSG
) != JIM_OK
)
497 Jim_IncrRefCount(argv
[2]);
498 id
= Jim_CreateTimeHandler(interp
, ms
, JimAfterTimeHandler
, argv
[2],
499 JimAfterTimeEventFinalizer
);
500 objPtr
= Jim_NewStringObj(interp
, NULL
, 0);
501 Jim_AppendString(interp
, objPtr
, "after#", -1);
502 idObjPtr
= Jim_NewIntObj(interp
, id
);
503 Jim_IncrRefCount(idObjPtr
);
504 Jim_AppendObj(interp
, objPtr
, idObjPtr
);
505 Jim_DecrRefCount(interp
, idObjPtr
);
506 Jim_SetResult(interp
, objPtr
);
512 const char *tok
= Jim_GetString(argv
[2], &tlen
);
513 if ( sscanf(tok
,"after#%lld",&id
) == 1) {
514 remain
= Jim_DeleteTimeHandler(interp
, id
);
516 Jim_SetResult(interp
, Jim_NewIntObj(interp
, remain
));
520 Jim_SetResultString(interp
, "invalid event" , -1);
524 fprintf(stderr
,"unserviced option to after %d\n",option
);
529 /* This extension is not dynamically loaded, instead it's linked statically,
530 which is why we shouldn't use the unspecific 'Jim_OnLoad' name */
531 int Jim_EventLoopOnLoad(Jim_Interp
*interp
)
533 Jim_EventLoop
*eventLoop
;
535 Jim_InitExtension(interp
);
536 if (Jim_PackageProvide(interp
, "eventloop", "1.0", JIM_ERRMSG
) != JIM_OK
)
539 eventLoop
= Jim_Alloc(sizeof(*eventLoop
));
540 eventLoop
->fileEventHead
= NULL
;
541 eventLoop
->timeEventHead
= NULL
;
542 eventLoop
->timeEventNextId
= 1;
543 Jim_SetAssocData(interp
, "eventloop", JimELAssocDataDeleProc
, eventLoop
);
545 Jim_CreateCommand(interp
, "vwait", JimELVwaitCommand
, NULL
, NULL
);
546 Jim_CreateCommand(interp
, "after", JimELAfterCommand
, NULL
, NULL
);
548 /* Export events API */
549 Jim_RegisterApi(interp
, "Jim_CreateFileHandler", Jim_CreateFileHandler
);
550 Jim_RegisterApi(interp
, "Jim_DeleteFileHandler", Jim_DeleteFileHandler
);
551 Jim_RegisterApi(interp
, "Jim_CreateTimeHandler", Jim_CreateTimeHandler
);
552 Jim_RegisterApi(interp
, "Jim_DeleteTimeHandler", Jim_DeleteTimeHandler
);
553 Jim_RegisterApi(interp
, "Jim_ProcessEvents", Jim_ProcessEvents
);
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)