~maresja1/+junk/helenos_qemu_porting

« back to all changes in this revision

Viewing changes to uspace/lib/c/generic/thread.c

  • Committer: Jan Mares
  • Date: 2015-01-31 12:40:12 UTC
  • Revision ID: jan@localhost.localdomain-20150131124012-o9p3o06x3u15voyz
Added join fot thread, failing to get thread_id.

Show diffs side-by-side

added added

removed removed

Lines of Context:
43
43
#include <async.h>
44
44
#include <errno.h>
45
45
#include <as.h>
 
46
#include <stdio.h>
46
47
#include "private/thread.h"
 
48
#include "../include/thread.h"
 
49
#include "../include/fibril_synch.h"
47
50
 
48
51
#ifdef FUTEX_UPGRADABLE
49
52
#include <rcu.h>
50
53
#endif
51
 
 
 
54
typedef enum{
 
55
    THREAD_JOINABLE,
 
56
    THREAD_EXITED,
 
57
    THREAD_DETACHED
 
58
} thread_state_t;
 
59
 
 
60
typedef struct{
 
61
    uspace_arg_t arg;
 
62
    thread_id_t id;
 
63
    fibril_mutex_t state_lock;
 
64
    fibril_condvar_t state_condvar;
 
65
    thread_retval_t retval;
 
66
    thread_state_t state;
 
67
    atomic_t ref_count;
 
68
} thread_internal_t;
 
69
 
 
70
static futex_t threads_protect = FUTEX_INITIALIZER;
 
71
static thread_internal_t **threads = NULL;
 
72
 
 
73
static void thread_del(thread_internal_t *thread);
 
74
 
 
75
static void thread_add(thread_internal_t *thread);
 
76
 
 
77
static thread_internal_t *thread_get(thread_id_t id);
 
78
 
 
79
static thread_internal_t *thread_alloc(void);
52
80
 
53
81
/** Main thread function.
54
82
 *
71
99
        rcu_register_fibril();
72
100
        futex_upgrade_all_and_wait();
73
101
#endif
74
 
        
75
 
        uarg->uspace_thread_function(uarg->uspace_thread_arg);
 
102
        thread_retval_t retval = uarg->uspace_thread_function(uarg->uspace_thread_arg);
76
103
        /*
77
104
         * XXX: we cannot free the userspace stack while running on it
78
105
         *
87
114
        rcu_deregister_fibril();
88
115
#endif
89
116
        
90
 
        fibril_teardown(fibril);
 
117
//      fibril_teardown(fibril);
91
118
        
92
 
        thread_exit(0);
 
119
        thread_exit(retval);
93
120
}
94
121
 
95
122
/** Create userspace thread.
104
131
 *
105
132
 * @return Zero on success or a code from @ref errno.h on failure.
106
133
 */
107
 
int thread_create(void (* function)(void *), void *arg, const char *name,
 
134
int thread_create(void* (*function)(void *), void *arg, const char *name,
108
135
    thread_id_t *tid)
109
136
{
110
 
        uspace_arg_t *uarg =
111
 
            (uspace_arg_t *) malloc(sizeof(uspace_arg_t));
112
 
        if (!uarg)
 
137
    thread_internal_t *thread = thread_alloc();
 
138
        if (!thread)
113
139
                return ENOMEM;
114
 
        
115
 
        size_t stack_size = stack_size_get();
 
140
 
 
141
    uspace_arg_t *uarg = &thread->arg;
 
142
 
 
143
 
 
144
    size_t stack_size = stack_size_get();
116
145
        void *stack = as_area_create(AS_AREA_ANY, stack_size,
117
146
            AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE | AS_AREA_GUARD |
118
147
            AS_AREA_LATE_RESERVE);
120
149
                free(uarg);
121
150
                return ENOMEM;
122
151
        }
123
 
        
 
152
 
 
153
 
124
154
        /* Make heap thread safe. */
125
155
        malloc_enable_multithreaded();
126
156
        
132
162
        uarg->uspace_uarg = uarg;
133
163
        
134
164
        int rc = __SYSCALL4(SYS_THREAD_CREATE, (sysarg_t) uarg,
135
 
            (sysarg_t) name, (sysarg_t) str_size(name), (sysarg_t) tid);
136
 
        
137
 
        if (rc != EOK) {
 
165
            (sysarg_t) name, (sysarg_t) str_size(name), (sysarg_t) &thread->id);
 
166
 
 
167
    thread_add(thread);
 
168
 
 
169
    if (rc != EOK) {
138
170
                /*
139
171
                 * Failed to create a new thread.
140
172
                 * Free up the allocated data.
142
174
                as_area_destroy(stack);
143
175
                free(uarg);
144
176
        }
145
 
        
 
177
 
 
178
    if(tid){
 
179
        *tid = thread->id;
 
180
    }
 
181
 
146
182
        return rc;
147
183
}
148
184
 
 
185
thread_internal_t *thread_alloc(void) {
 
186
    thread_internal_t *thread = (thread_internal_t*)malloc(sizeof(thread_internal_t));
 
187
    if(thread){
 
188
        thread->state = THREAD_JOINABLE;
 
189
        atomic_set(&thread->ref_count,1);
 
190
        fibril_mutex_initialize(&thread->state_lock);
 
191
        fibril_condvar_initialize(&thread->state_condvar);
 
192
    }
 
193
    return thread;
 
194
}
 
195
 
 
196
void thread_add(thread_internal_t *thread)
 
197
{
 
198
    futex_down(&threads_protect);
 
199
        if(threads == NULL){
 
200
            threads = malloc(sizeof(thread_internal_t*)* THREAD_MAX);
 
201
        }
 
202
        threads[thread->id] = thread;
 
203
        fprintf(stdout, "Thread id: %"PRIu64" add to address:%p",thread->id,thread);
 
204
    futex_up(&threads_protect);
 
205
}
 
206
 
 
207
thread_internal_t *thread_get(thread_id_t id)
 
208
{
 
209
    thread_internal_t *ret;
 
210
    futex_down(&threads_protect);
 
211
        ret = threads[id];
 
212
    futex_up(&threads_protect);
 
213
    return ret;
 
214
}
 
215
 
 
216
void thread_del(thread_internal_t *thread)
 
217
{
 
218
    futex_down(&threads_protect);
 
219
        threads[thread->id] = NULL;
 
220
    fprintf(stdout, "Thread id: %"PRIu64" with address:%p deleted.",thread->id,thread);
 
221
    futex_up(&threads_protect);
 
222
}
 
223
 
 
224
static void thread_dealloc(thread_internal_t *thread)
 
225
{
 
226
    if(atomic_predec(&thread->ref_count)){
 
227
        return;
 
228
    }
 
229
    //TODO dealloc thread
 
230
}
 
231
 
149
232
/** Terminate current thread.
150
233
 *
151
234
 * @param status Exit status. Currently not used.
152
235
 *
153
236
 */
154
 
void thread_exit(int status)
 
237
void thread_exit(thread_retval_t status)
155
238
{
156
 
        __SYSCALL1(SYS_THREAD_EXIT, (sysarg_t) status);
157
 
        
 
239
    thread_id_t id = thread_get_id();
 
240
    fprintf(stdout, "Exit id:%"PRIu64"\n", id);
 
241
    thread_internal_t *thread = thread_get(id);
 
242
    fprintf(stdout, " of address:%p",thread);
 
243
    fprintf(stdout, " and id:%"PRIu64"\n", thread->id);
 
244
 
 
245
    fibril_mutex_lock(&thread->state_lock);
 
246
    if(thread->state == THREAD_JOINABLE){
 
247
        thread->state = THREAD_EXITED;
 
248
        thread->retval = status;
 
249
        fibril_condvar_broadcast(&thread->state_condvar);
 
250
    }
 
251
    fibril_mutex_unlock(&thread->state_lock);
 
252
 
 
253
//    fi
 
254
        __SYSCALL1(SYS_THREAD_EXIT, (sysarg_t) 0);
 
255
 
 
256
    thread_del(thread);
158
257
        /* Unreachable */
159
258
        while (1);
160
259
}
161
260
 
 
261
 
162
262
/** Detach thread.
163
263
 *
164
264
 * Currently not implemented.
178
278
 *
179
279
 * @return Thread exit status.
180
280
 */
181
 
int thread_join(thread_id_t thread)
 
281
int thread_join(thread_id_t thread_id, thread_retval_t *retval)
182
282
{
183
 
        return 0;
 
283
    fprintf(stdout, "Join to:%"PRIu64"\n", thread_id);
 
284
    int err = 0;
 
285
    thread_internal_t *thread = thread_get(thread_id);
 
286
    if(thread == NULL){
 
287
        return EINVAL;
 
288
    }
 
289
 
 
290
 
 
291
    fibril_mutex_lock(&thread->state_lock);
 
292
    fprintf(stdout, "*");
 
293
    /* Rely on pthread_cond_wait being a cancellation point to make
 
294
     pthread_join one too.  */
 
295
    while (thread->state == THREAD_JOINABLE){
 
296
        fibril_condvar_wait(&thread->state_condvar,&thread->state_lock);
 
297
        fprintf(stdout, "@");
 
298
    }
 
299
 
 
300
 
 
301
    switch (thread->state)
 
302
    {
 
303
        case THREAD_EXITED:
 
304
            /* THREAD has already exited.  Salvage its exit status.  */
 
305
            if (retval)
 
306
                *retval = thread->retval;
 
307
 
 
308
            fibril_mutex_unlock(&thread->state_lock);
 
309
 
 
310
            thread_dealloc(thread);
 
311
            break;
 
312
 
 
313
        default:
 
314
            /* Thou shalt not join non-joinable threads!  */
 
315
            fibril_mutex_unlock (&thread->state_lock);
 
316
            err = EINVAL;
 
317
            break;
 
318
    }
 
319
 
 
320
    fprintf(stderr, "Join end:%"PRIu64"\n", thread_id);
 
321
        return err;
184
322
}
185
323
 
186
324
/** Get current thread ID.
192
330
        thread_id_t thread_id;
193
331
 
194
332
        (void) __SYSCALL1(SYS_THREAD_GET_ID, (sysarg_t) &thread_id);
 
333
    fprintf(stdout, "Thread id:%"PRIu64"\n", thread_id);
195
334
 
196
335
        return thread_id;
197
336
}