-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy paththread.c
135 lines (113 loc) · 3.36 KB
/
thread.c
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
/* Boron Thread */
#include <math.h>
#include <time.h>
#ifdef _WIN32
static DWORD WINAPI threadRoutine( LPVOID arg )
#else
static void* threadRoutine( void* arg )
#endif
{
UThread* ut = (UThread*) arg;
UBuffer* bin = &BT->tbin;
if( ! boron_evalUtf8( ut, bin->ptr.c, bin->used ) )
{
UBuffer str;
UCell* ex = ur_exception( ut );
if( ! ur_is(ex, UT_WORD) || ur_atom(ex) != UR_ATOM_QUIT )
{
ur_strInit( &str, UR_ENC_UTF8, 0 );
ur_toText( ut, ex, &str );
ur_strTermNull( &str );
puts( str.ptr.c );
ur_strFree( &str );
}
}
ur_destroyThread( ut );
return 0;
}
extern void boron_installThreadPort( UThread*, const UCell*, UThread* );
extern void boron_setJoinThread( UThread*, const UCell*, OSThread );
/*-cf-
thread
routine string!/block!
/port Create thread port.
return: Thread port or unset!
Create a new thread to run a routine.
A string! routine argument is preferred as a block! will be converted to
a string! before it can be passed to the thread.
If the /port option is used the new thread will have a port! bound to the
'thread-port word that is connected to the one returned from the function.
This can be used for bi-directional communication.
Each thread has it's own data store, so series values passed through the
port will become empty on write as ownership is transferred.
Only one series can be sent through the port on each write, so writing a
block! that contains series values will throw an error.
Words not bound to the shared environment will become unbound in the
reading thread.
*/
CFUNC( cfunc_thread )
{
#define OPT_THREAD_PORT 0x01
OSThread osThr;
UThread* child;
UBuffer code;
#ifdef _WIN32
DWORD winId;
#endif
ur_strInit( &code, UR_ENC_UTF8, 0 );
if( ur_is(a1, UT_STRING) )
{
USeriesIter si;
ur_seriesSlice( ut, &si, a1 );
ur_strAppend( &code, si.buf, si.it, si.end );
}
else if( ur_is(a1, UT_BLOCK) )
{
ur_toStr( ut, a1, &code, -1 );
}
else
return ur_error( ut, UR_ERR_TYPE, "thread expected string!/block!" );
child = ur_makeThread( ut );
if( ! child )
{
ur_strFree( &code );
return ur_error( ut, UR_ERR_INTERNAL, "No memory for thread" );
}
// Copy code to child temp. binary.
{
UBuffer* bin = &((BoronThread*) child)->tbin;
bin->used = 0;
ur_binAppendData( bin, code.ptr.b, code.used );
ur_strFree( &code );
}
ur_setId(res, UT_UNSET);
if( CFUNC_OPTIONS & OPT_THREAD_PORT )
{
if( ! port_thread.open( ut, &port_thread, res, 0, res ) )
return UR_THROW;
boron_installThreadPort( ut, res, child );
}
#ifdef _WIN32
osThr = CreateThread( NULL, 0, threadRoutine, child, 0, &winId );
if( osThr == NULL )
#else
if( pthread_create( &osThr, 0, threadRoutine, child ) != 0 )
#endif
{
return ur_error( ut, UR_ERR_INTERNAL, "Could not create thread" );
}
if( CFUNC_OPTIONS & OPT_THREAD_PORT )
{
// Will pthread_join() when port closed.
boron_setJoinThread( ut, res, osThr );
}
#ifndef _WIN32
else
{
// Detach to automatically release thread memory when it exits.
pthread_detach( osThr );
}
#endif
return UR_OK;
}
/*EOF*/