1/** \file
2 *  \brief Example application using threads - a more complex
3 *         example using synchronisation
4 */
5
6/*
7 * Copyright (c) 2010, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <string.h>
17
18#include <barrelfish/barrelfish.h>
19
20#include <barrelfish/threads.h>
21
22
23// data to pass to each thread
24struct my_thread_data {
25    int t_num;
26    struct thread *t_id;
27    struct thread_mutex *mutex;
28    int *start_cntr;
29    struct thread_sem *sem;
30    int ret;
31};
32
33// the code that each thread runs
34static int my_thread(void *data)
35{
36    struct my_thread_data *t_data = data;
37    int thread_num = t_data->t_num;
38
39    thread_mutex_lock(t_data->mutex);
40    (*(t_data->start_cntr))++;
41    thread_mutex_unlock(t_data->mutex);
42
43    printf("this is thread %d saying hello\n", thread_num);
44
45    thread_sem_post(t_data->sem);
46
47    return thread_num;
48}
49
50int main(int argc, char *argv[])
51{
52    errval_t err;
53    int num_threads = 0;
54
55    // # of threads to start
56    if (argc == 2) {
57        num_threads = atoi(argv[1]);
58        debug_printf("starting %d threads\n", num_threads);
59    } else {
60        printf("usage %s num_threads\n", argv[0]);
61        return EXIT_FAILURE;
62    }
63
64
65    // setup lock, counter, and semaphore
66    struct thread_mutex mutex = THREAD_MUTEX_INITIALIZER;
67    thread_mutex_init(&mutex);
68    int start_cntr = 0;
69    struct thread_sem sem = THREAD_SEM_INITIALIZER;
70    thread_sem_init(&sem, 0);
71
72    // set thread argument data
73    struct my_thread_data *t_data;
74    t_data = malloc(num_threads*sizeof(struct my_thread_data));
75    assert(t_data != NULL);
76
77
78    // start threads
79    for (int i = 0; i < num_threads; i++) {
80        t_data[i].t_num = i;
81        t_data[i].mutex = &mutex;
82        t_data[i].start_cntr = &start_cntr;
83        t_data[i].sem = &sem;
84
85        t_data[i].t_id = thread_create(my_thread, &(t_data[i]));
86        if (t_data[i].t_id == NULL) {
87            debug_printf("ERROR: starting thread %d\n", i);
88        }
89        debug_printf("started thread %d\n", i);
90    }
91
92    // wait until all started
93    while (start_cntr != num_threads) {
94        thread_yield();
95    }
96
97    debug_printf("all threads started\n");
98
99    // wait until all finished
100    for (int i = 0; i < num_threads; i++) {
101        thread_sem_wait(&sem);
102    }
103
104    debug_printf("all threads finished\n");
105
106    // cleanup: join all threads
107    for (int i = 0; i < num_threads; i++) {
108        err = thread_join(t_data[i].t_id, &(t_data[i].ret));
109        if (err_is_ok(err)) {
110            debug_printf("joined thread %d, return value: %d\n",
111                         i, t_data[i].ret);
112        } else {
113            DEBUG_ERR(err, "in thread_join for thread %d", i);
114        }
115    }
116
117    debug_printf("finished.\n");
118
119    return EXIT_SUCCESS;
120}
121
122