summaryrefslogtreecommitdiffstats
path: root/doc/vwait.n
blob: 43a26182d2a16d4741f2622baa1067a3ef65897a (plain)
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
'\"
'\" Copyright (c) 1995-1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: vwait.n,v 1.11 2009/07/11 11:26:20 dkf Exp $
'\" 
.so man.macros
.TH vwait n 8.0 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
vwait \- Process events until a variable is written
.SH SYNOPSIS
\fBvwait\fR \fIvarName\fR
.BE
.SH DESCRIPTION
.PP
This command enters the Tcl event loop to process events, blocking
the application if no events are ready.  It continues processing
events until some event handler sets the value of the global variable
\fIvarName\fR.  Once \fIvarName\fR has been set, the \fBvwait\fR
command will return as soon as the event handler that modified
\fIvarName\fR completes.  The \fIvarName\fR argument is always interpreted as
a variable name with respect to the global namespace, but can refer to any
namespace's variables if the fully-qualified name is given.
.PP
In some cases the \fBvwait\fR command may not return immediately
after \fIvarName\fR is set.  This happens if the event handler
that sets \fIvarName\fR does not complete immediately.  For example,
if an event handler sets \fIvarName\fR and then itself calls
\fBvwait\fR to wait for a different variable, then it may not return
for a long time.  During this time the top-level \fBvwait\fR is
blocked waiting for the event handler to complete, so it cannot
return either.
.PP
To be clear, \fImultiple \fBvwait\fI calls will nest and will not happen in
parallel\fR.  The outermost call to \fBvwait\fR will not return until all the
inner ones do.  It is recommended that code should never nest \fBvwait\fR
calls (by avoiding putting them in event callbacks) but when that is not
possible, care should be taken to add interlock variables to the code to
prevent all reentrant calls to \fBvwait\fR that are not \fIstrictly\fR
necessary. Be aware that the synchronous modes of operation of some Tcl
packages (e.g.,\ \fBhttp\fR) use \fBvwait\fR internally; if using the event
loop, it is best to use the asynchronous callback-based modes of operation of
those packages where available.
.SH EXAMPLES
.PP
Run the event-loop continually until some event calls \fBexit\fR.
(You can use any variable not mentioned elsewhere, but the name
\fIforever\fR reminds you at a glance of the intent.)
.PP
.CS
\fBvwait\fR forever
.CE
.PP
Wait five seconds for a connection to a server socket, otherwise
close the socket and continue running the script:
.PP
.CS
# Initialise the state
after 5000 set state timeout
set server [socket -server accept 12345]
proc accept {args} {
   global state connectionInfo
   set state accepted
   set connectionInfo $args
}

# Wait for something to happen
\fBvwait\fR state

# Clean up events that could have happened
close $server
after cancel set state timeout

# Do something based on how the vwait finished...
switch $state {
   timeout {
      puts "no connection on port 12345"
   }
   accepted {
      puts "connection: $connectionInfo"
      puts [lindex $connectionInfo 0] "Hello there!"
   }
}
.CE
.PP
A command that will wait for some time delay by waiting for a namespace
variable to be set.  Includes an interlock to prevent nested waits.
.PP
.CS
namespace eval example {
   variable v done
   proc wait {delay} {
      variable v
      if {$v ne "waiting"} {
         set v waiting
         after $delay [namespace code {set v done}]
         \fBvwait\fR [namespace which -variable v]
      }
      return $v
   }
}
.CE
.PP
When running inside a \fBcoroutine\fR, an alternative to using \fBvwait\fR is
to \fByield\fR to an outer event loop and to get recommenced when the variable
is set, or at an idle moment after that.
.PP
.CS
coroutine task apply {{} {
   # simulate [after 1000]
   after 1000 [info coroutine]
   yield

   # schedule the setting of a global variable, as normal
   after 2000 {set var 1}

   # simulate [\fBvwait\fR var]
   proc updatedVar {task args} {
      after idle $task
      trace remove variable ::var write "updatedVar $task"
   }
   trace add variable ::var write "updatedVar [info coroutine]"
   yield
}}
.CE
.SH "SEE ALSO"
global(n), update(n)
.SH KEYWORDS
event, variable, wait
'\" Local Variables:
'\" mode: nroff
'\" fill-column: 78
'\" End: