Source

plan9port / man / man3 / thread.3

Full commit
  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
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
.TH THREAD 3
.SH NAME
alt,
chancreate,
chanfree,
chanprint,
chansetname,
mainstacksize,
proccreate,
procdata,
recv,
recvp,
recvul,
send,
sendp,
sendul,
nbrecv,
nbrecvp,
nbrecvul,
nbsend,
nbsendp,
nbsendul,
threadcreate,
threaddata,
threadexec,
threadexecl,
threadexits,
threadexitsall,
threadgetgrp,
threadgetname,
threadint,
threadintgrp,
threadkill,
threadkillgrp,
threadmain,
threadnotify,
threadid,
threadpid,
threadpin,
threadunpin,
threadsetgrp,
threadsetname,
threadsetstate,
threadspawn,
threadspawnd,
threadspawnl,
threadwaitchan,
yield \- thread and proc management
.SH SYNOPSIS
.PP
.EX
.ta 4n +4n +4n +4n +4n +4n +4n
#include <u.h>
#include <libc.h>
#include <thread.h>
.sp
#define	CHANEND		0
#define	CHANSND		1
#define	CHANRCV		2
#define	CHANNOP		3
#define	CHANNOBLK	4
.sp
.ta \w'    'u +\w'Channel 'u
typedef struct Alt Alt;
struct Alt {
	Channel	*c;
	void	*v;
	int	op;
	Channel	**tag;
	int	entryno;
	char	*name;
};
.fi
.de XX
.if t .sp 0.5
.if n .sp
..
.PP
.nf
.ft L
.ta \w'\fLChannel* 'u +4n +4n +4n +4n
void	threadmain(int argc, char *argv[])
int	mainstacksize
int	proccreate(void (*fn)(void*), void *arg, uint stacksize)
int	threadcreate(void (*fn)(void*), void *arg, uint stacksize)
void	threadexits(char *status)
void	threadexitsall(char *status)
void	yield(void)
int	threadpin(void)
int	threadunpin(void)
.XX
int	threadid(void)
int	threadgrp(void)
int	threadsetgrp(int group)
int	threadpid(int id)
.XX
int	threadint(int id)
int	threadintgrp(int group)
int	threadkill(int id)
int	threadkillgrp(int group)
.XX
void	threadsetname(char *name)
char*	threadgetname(void)
.XX
void**	threaddata(void)
void**	procdata(void)
.XX
Channel*	chancreate(int elsize, int nel)
void	chanfree(Channel *c)
.XX
int	alt(Alt *alts)
int	recv(Channel *c, void *v)
void*	recvp(Channel *c)
ulong	recvul(Channel *c)
int	nbrecv(Channel *c, void *v)
void*	nbrecvp(Channel *c)
ulong	nbrecvul(Channel *c)
int	send(Channel *c, void *v)
int	sendp(Channel *c, void *v)
int	sendul(Channel *c, ulong v)
int	nbsend(Channel *c, void *v)
int	nbsendp(Channel *c, void *v)
int	nbsendul(Channel *c, ulong v)
int	chanprint(Channel *c, char *fmt, ...)
.XX
int	threadspawnl(int fd[3], char *file, ...)
int	threadspawn(int fd[3], char *file, char *args[])
int	threadspawnd(int fd[3], char *file, char *args[], char *dir)
int	threadexecl(Channel *cpid, int fd[3], char *file, ...)
int	threadexec(Channel *cpid, int fd[3], char *file, char *args[])
Channel*	threadwaitchan(void)
.XX
int	threadnotify(int (*f)(void*, char*), int in)
.EE
.SH DESCRIPTION
.PP
The thread library provides parallel programming support similar to that
of the languages
Alef and Newsqueak.
Threads
and
procs
occupy a shared address space,
communicating and synchronizing through
.I channels
and shared variables.
.PP
A
.I proc
is a Plan 9 process that contains one or more cooperatively scheduled
.IR threads .
Programs using threads must replace
.I main
by
.IR threadmain .
The thread library provides a
.I main
function that sets up a proc with a single thread executing
.I threadmain
on a stack of size
.I mainstacksize
(default eight kilobytes).
To set
.IR mainstacksize ,
declare a global variable
initialized to the desired value
.RI ( e.g. ,
.B int
.B mainstacksize
.B =
.BR 1024 ).
.PP
.I Threadcreate
creates a new thread in the calling proc, returning a unique integer
identifying the thread; the thread
executes
.I fn(arg)
on a stack of size
.IR stacksize .
Thread stacks are allocated in shared memory, making it valid to pass 
pointers to stack variables between threads and procs.
.I Proccreate
creates a new proc, and inside that proc creates
a single thread as
.I threadcreate
would,
returning the id of the created thread.
.\" .I Procrfork
.\" creates the new proc by calling
.\" .B rfork
.\" (see
.\" .IR fork (3))
.\" with flags
.\" .BR RFPROC|RFMEM|RFNOWAIT| \fIrforkflag\fR.
.\" (The thread library depends on all its procs
.\" running in the same rendezvous group.
.\" Do not include
.\" .B RFREND
.\" in
.\" .IR rforkflag .)
.\" .I Proccreate
.\" is identical to 
.\" .I procrfork
.\" with
.\" .I rforkflag
.\" set to zero.
Be aware that the calling thread may continue
execution before
the newly created proc and thread
are scheduled.
Because of this,
.I arg
should not point to data on the stack of a function that could
return before the new process is scheduled.
.PP
.I Threadexits
terminates the calling thread.
If the thread is the last in its proc,
.I threadexits
also terminates the proc, using
.I status
as the exit status.
.I Threadexitsall
terminates all procs in the program,
using
.I status
as the exit status.
.PP
When the last thread in
.IR threadmain 's
proc exits, the program will appear to its parent to have exited.
The remaining procs will still run together, but as a background program.
.PP
The threads in a proc are coroutines, scheduled nonpreemptively
in a round-robin fashion.
A thread must explicitly relinquish control of the processor
before another thread in the same proc is run.
Calls that do this are
.IR yield ,
.IR proccreate ,
.IR threadexec ,
.IR threadexecl ,
.IR threadexits ,
.IR threadspawn ,
.IR threadspawnd ,
.IR threadspawnl ,
.IR alt ,
.IR send ,
and
.I recv
(and the calls related to
.I send
and
.IR recv \(emsee
their descriptions further on).
Procs are scheduled by the operating system.
Therefore, threads in different procs can preempt one another
in arbitrary ways and should synchronize their
actions using
.B qlocks
(see
.IR lock (3))
or channel communication.
System calls such as
.IR read (3)
block the entire proc;
all threads in a proc block until the system call finishes.
.PP
.I Threadpin
disables scheduling inside a proc, `pinning' the current
thread as the only runnable one in the current proc.
.I Threadunpin
reenables scheduling, allowing other procs to run once the current
thread relinquishes the processor.
.I Threadpin
and
.I threadunpin
can lead to deadlock.
Used carefully, they can make library routines that use
.B qlocks
appear atomic relative to the current proc, like a system call.
.PP
As mentioned above, each thread has a unique integer thread id.
Thread ids are not reused; they are unique across the life of the program.
.I Threadid
returns the id for the current thread.
Each thread also has a thread group id.
The initial thread has a group id of zero.
Each new thread inherits the group id of
the thread that created it.
.I Threadgrp
returns the group id for the current thread;
.I threadsetgrp
sets it.
.I Threadpid
returns the pid of the Plan 9 process containing
the thread identified by
.IR id ,
or \-1
if no such thread is found.
.PP
.I Threadint
interrupts a thread that is blocked in a channel operation
or system call.
.I Threadintgrp
interrupts all threads with the given group id.
.I Threadkill
marks a thread to die when it next relinquishes the processor
(via one of the calls listed above).
If the thread is blocked in a channel operation or system call,
it is also interrupted.
.I Threadkillgrp
kills all threads with the given group id.
Note that
.I threadkill
and
.I threadkillgrp
will not terminate a thread that never relinquishes
the processor.
.PP
Primarily for debugging,
threads can have string names associated with them.
.I Threadgetname
returns the current thread's name;
.I threadsetname
sets it.
The pointer returned by
.I threadgetname
is only valid until the next call to
.IR threadsetname .
.PP
Also for debugging,
threads have a string state associated with them.
.I Threadsetstate
sets the state string.
There is no 
.IR threadgetstate ;
since the thread scheduler resets the state to
.B Running
every time it runs the thread, 
it is only useful for debuggers to inspect the state.
.PP
.I Threaddata
returns a pointer to a per-thread pointer
that may be modified by threaded programs for
per-thread storage.
Similarly, 
.I procdata
returns a pointer to a per-proc pointer.
.PP
.I Threadexecl
and
.I threadexec
are threaded analogues of
.I exec
and
.I execl
(see
.IR exec (3));
on success,
they replace the calling thread
and invoke the external program, never returning.
(Unlike on Plan 9, the calling thread need not be the only thread in its proc\(emthe other
threads will continue executing.)
On error, they return \-1.
If
.I cpid
is not null, the pid of the invoked program
will be sent along
.I cpid
(using
.IR sendul )
once the program has been started, or \-1 will be sent if an
error occurs.
.I Threadexec
and
.I threadexecl
will not access their arguments after sending a result
along
.IR cpid .
Thus, programs that malloc the
.I argv
passed to
.I threadexec
can safely free it once they have
received the
.I cpid
response.
.PP
.I Threadexecl
and
.I threadexec
will duplicate 
(see
.IR dup (3))
the three file descriptors in
.I fd 
onto standard input, output, and error for the external program
and then close them in the calling thread.
Beware of code that sets
.IP
.EX
fd[0] = 0;
fd[1] = 1;
fd[2] = 2;
.EE
.LP
to use the current standard files.  The correct code is
.IP
.EX
fd[0] = dup(0, -1);
fd[1] = dup(1, -1);
fd[2] = dup(2, -1);
.EE
.PP
.I Threadspawnl
and
.I threadspawn
are like
.I threadexecl
and
.I threadexec
but do not replace the current thread.
They return the pid of the invoked program on success, or
\-1 on error.
.I Threadspawnd
is like
.I threadspawn
but takes as its final argument the directory in which to run the invoked program.
The child will attempt to change into that directory before running the program,
but it is only best effort: failure to change into the directory does not
stop the running of the program.
.PP
.I Threadwaitchan
returns a channel of pointers to
.B Waitmsg
structures (see
.IR wait (3)).
When an exec'ed process exits, a pointer to a
.B Waitmsg
is sent to this channel.
These
.B Waitmsg
structures have been allocated with
.IR malloc (3)
and should be freed after use.
.PP
A
.B Channel
is a buffered or unbuffered queue for fixed-size messages.
Procs and threads
.I send
messages into the channel and
.I recv
messages from the channel.  If the channel is unbuffered, a
.I send
operation blocks until the corresponding
.I recv
operation occurs and
.IR "vice versa" .
.IR Chancreate
allocates a new channel 
for messages of size
.I elsize 
and with a buffer holding
.I nel
messages.
If
.I nel
is zero, the channel is unbuffered.
.I Chanfree
frees a channel that is no longer used.
.I Chanfree
can be called by either sender or receiver after the last item has been
sent or received.  Freeing the channel will be delayed if there is a thread
blocked on it until that thread unblocks (but
.I chanfree
returns immediately).
.PP
The
.B name
element in the
.B Channel
structure is a description intended for use in debugging.
.I Chansetname
sets the name.
.PP
.I Send
sends the element pointed at by
.I v
to the channel
.IR c .
If
.I v
is null, zeros are sent.
.I Recv
receives an element from
.I c
and stores it in
.IR v .
If
.I v
is null,
the received value is discarded.
.I Send
and
.I recv
return 1 on success, \-1 if interrupted.
.I Nbsend
and
.I nbrecv
behave similarly, but return 0 rather than blocking.
.PP
.IR Sendp ,
.IR nbsendp ,
.IR sendul ,
and
.I nbsendul
send a pointer or an unsigned long; the channel must
have been initialized with the appropriate
.IR elsize .
.IR Recvp ,
.IR nbrecvp ,
.IR recvul ,
and
.I nbrecvul
receive a pointer or an unsigned long;
they return zero when a zero is received,
when interrupted, or
(for
.I nbrecvp
and
.IR nbrecvul )
when the operation would have blocked.
To distinguish between these three cases,
use
.I recv
or
.IR nbrecv .
.PP
.I Alt
can be used to recv from or send to one of a number of channels,
as directed by an array of
.B Alt
structures,
each of which describes a potential send or receive operation.
In an
.B Alt
structure,
.B c
is the channel;
.B v
the value pointer (which may be null); and
.B op
the operation:
.B CHANSND
for a send operation,
.B CHANRECV
for a recv operation;
.B CHANNOP
for no operation
(useful
when
.I alt
is called with a varying set of operations).
The array of
.B Alt
structures is terminated by an entry with
.I op
.B CHANEND
or
.BR CHANNOBLK .
If at least one
.B Alt
structure can proceed, one of them is
chosen at random to be executed.
.I Alt
returns the index of the chosen structure.
If no operations can proceed and the list is terminated with
.BR CHANNOBLK ,
.I alt
returns the index of the terminating
.B CHANNOBLK
structure.
Otherwise,
.I alt
blocks until one of the operations can proceed,
eventually returning the index of the structure executes.
.I Alt
returns \-1 when interrupted.
The
.B tag
and
.B entryno
fields in the
.B Alt
structure are used internally by
.I alt
and need not be initialized.
They are not used between
.I alt
calls.
.PP
.I Chanprint
formats its arguments in the manner of
.IR print (3)
and sends the result to the channel
.IR c.
The string delivered by
.I chanprint
is allocated with
.IR malloc (3)
and should be freed upon receipt.
.PP
Thread library functions do not return on failure;
if errors occur, the entire program is aborted.
.PP
Threaded programs should use
.I threadnotify
in place of
.I atnotify
(see
.IR notify (3)).
.PP
It is safe to use
.IR sysfatal (3)
in threaded programs.
.I Sysfatal
will print the error string and call
.IR threadexitsall .
.PP
It is not safe to call
.IR rfork
in a threaded program, except to call
.B rfork(RFNOTEG)
from the main proc before any other procs have been created.
To create new processes, use
.IR proccreate .
.\" .PP
.\" It is safe to use 
.\" .IR rfork
.\" (see
.\" .IR fork (3))
.\" to manage the namespace, file descriptors, note group, and environment of a
.\" single process.
.\" That is, it is safe to call
.\" .I rfork
.\" with the flags
.\" .BR RFNAMEG ,
.\" .BR RFFDG ,
.\" .BR RFCFDG ,
.\" .BR RFNOTEG ,
.\" .BR RFENVG ,
.\" and
.\" .BR RFCENVG.
.\" (To create new processes, use
.\" .I proccreate
.\" and 
.\" .IR procrfork .)
.\" As mentioned above,
.\" the thread library depends on all procs being in the
.\" same rendezvous group; do not change the rendezvous
.\" group with
.\" .IR rfork .
.SH FILES
.B \*9/acid/thread
contains useful
.IR acid (1)
functions for debugging threaded programs.
.PP
.B \*9/src/libthread/test
contains some example programs.
.SH SOURCE
.B \*9/src/libthread
.SH SEE ALSO
.IR intro (3),
.IR ioproc (3)
.SH BUGS
To avoid name conflicts,
.IR alt ,
.IR nbrecv ,
.IR nbrecvp ,
.IR nbrecvul ,
.IR nbsend ,
.IR nbsendp ,
.IR nbsendul ,
.IR recv ,
.IR recvp ,
.IR recvul ,
.IR send ,
.IR sendp ,
and
.IR sendul
are defined as macros that expand to
.IR chanalt ,
.IR channbrecv ,
and so on.
.I Yield
is defined as a macro that expands to
.IR threadyield .
See
.IR intro (3).
.PP
Threadint,
threadintgrp,
threadkill,
threadkillgrp and threadpid are unimplemented.
.PP
The implementation of
.I threadnotify
may not be correct.
.PP
There appears to be a race in the Linux NPTL
implementation of
.I pthread_exit .
Call
.I threadexitsall
rather than coordinating a simultaneous
.I threadexits
among many threads.