-
Notifications
You must be signed in to change notification settings - Fork 0
/
12_cthread_detach.c
150 lines (134 loc) · 2.76 KB
/
12_cthread_detach.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdbool.h>
#include <setjmp.h>
#include "clone.h"
typedef int (*cthread_f)(void *);
void
spin_lock(volatile bool *lock)
{
while (! __sync_bool_compare_and_swap(lock, 0, 1)) {};
}
void
spin_unlock(volatile bool *lock)
{
__sync_bool_compare_and_swap(lock, 1, 0);
}
struct cthread_stack {
pid_t tid;
void *stack;
struct cthread_stack *next;
};
struct cthread_stack *stack_list = NULL;
volatile bool last_stack_lock = false;
struct cthread {
int returned_code;
cthread_f func;
void *arg;
struct cthread_stack *stack;
bool lock;
bool is_finished;
bool is_detached;
jmp_buf jmp;
};
void
cthread_destroy(struct cthread *thread)
{
printf("thread is destroyed\n");
spin_lock(&last_stack_lock);
struct cthread_stack *iter = stack_list;
while (iter != NULL) {
if (iter->tid != 0)
break;
struct cthread_stack *next = iter->next;
free(iter->stack);
free(iter);
iter = next;
printf("a stack is freed\n");
}
thread->stack->next = iter;
stack_list = thread->stack;
spin_unlock(&last_stack_lock);
}
int
cthread_join(volatile struct cthread *thread)
{
printf("thread is joined\n");
while (! thread->is_finished)
sched_yield();
cthread_destroy((struct cthread *) thread);
return thread->returned_code;
}
int
cthread_runner(void *arg)
{
struct cthread *thread = (struct cthread *) arg;
if (setjmp(thread->jmp) == 0) {
thread->returned_code =
thread->func(thread->arg);
}
spin_lock(&thread->lock);
if (thread->is_detached)
cthread_destroy(thread);
thread->is_finished = true;
spin_unlock(&thread->lock);
return 0;
}
void
cthread_detach(struct cthread *thread)
{
spin_lock(&thread->lock);
if (thread->is_finished)
cthread_destroy(thread);
//sleep(1);
thread->is_detached = true;
spin_unlock(&thread->lock);
}
void
cthread_create(struct cthread *result, cthread_f func,
void *arg)
{
result->returned_code = 0;
result->func = func;
result->arg = arg;
result->is_finished = false;
result->is_detached = false;
result->lock = false;
result->stack = (struct cthread_stack *) malloc(sizeof(*result->stack));
result->stack->next = NULL;
thread_create_clone_tid(cthread_runner, (void *) result,
&result->stack->stack, &result->stack->tid);
}
void
cthread_exit(struct cthread *thread, int retcode)
{
thread->returned_code = retcode;
longjmp(thread->jmp, 1);
}
int
func(void *arg)
{
printf("thread started\n");
return 0;
}
int
main()
{
struct cthread thread[10];
for (int i = 0; i < 10; ++i) {
cthread_create(&thread[i], func, NULL);
cthread_detach(&thread[i]);
}
for (int i = 0; i < 10; ++i) {
if (! thread[i].is_finished) {
i = 0;
sched_yield();
}
}
printf("detached threads finished\n");
return 0;
}