Subversion Repositories HelenOS

Rev

Rev 2265 | Rev 2315 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2265 Rev 2309
Line 41... Line 41...
41
#include <synch/spinlock.h>
41
#include <synch/spinlock.h>
42
#include <time/delay.h>
42
#include <time/delay.h>
43
#include <panic.h>
43
#include <panic.h>
44
#include <print.h>
44
#include <print.h>
45
 
45
 
46
typedef struct  {
-
 
47
    uint32_t current_batch;
-
 
48
    uint32_t completed_batch;
-
 
49
    bool next_batch_waiting;
-
 
50
} rcu_global_t;
46
SPINLOCK_INITIALIZE(rcu_global_lock);
51
 
47
 
52
typedef struct rcu_callback_list {
48
typedef struct rcu_callback_list {
53
    struct rcu_callback_list* next;
49
    struct rcu_callback_list* next;
54
    void (*func)(void*);
50
    void (*func)(void*);
55
    void* data;
51
    void* data;
56
    bool* cpu_mask;
-
 
57
} rcu_callback_list_t;
52
} rcu_callback_list_t;
58
 
53
 
59
 
-
 
60
typedef struct {
54
typedef struct  {
61
    uint32_t current_batch_number;
55
#ifdef CONFIG_SMP 
62
    uint32_t QS_passed;
56
    bool* cpu_mask;
63
    bool QS_pending;
57
#endif
64
    rcu_callback_list_t* next_batch, *current_batch, *done_batch;
58
    rcu_callback_list_t* next_batch, *current_batch, *done_batch;
65
} rcu_percpu_t;
59
} rcu_global_t;
-
 
60
 
66
 
61
 
67
rcu_global_t _rcu_global;
62
rcu_global_t* _rcu_global;
68
rcu_percpu_t* _rcu_cpu_lists;
63
tasklet_descriptor_t* rcu_tasklet_desc;
69
 
64
 
70
void rcu_init(void)
65
void rcu_init(void)
71
{
66
{
-
 
67
#ifdef CONFIG_SMP 
-
 
68
    int i;
-
 
69
#endif
-
 
70
 
72
    _rcu_cpu_lists = malloc(sizeof(rcu_percpu_t)*config.cpu_count,0);
71
    _rcu_global = malloc(sizeof(rcu_global_t),0);
73
    _rcu_global.completed_batch = -1;
72
    _rcu_global->done_batch = NULL;
74
    _rcu_global.current_batch = -1;
73
    _rcu_global->current_batch = NULL;
75
    _rcu_global.next_batch_waiting = -1;
74
    _rcu_global->next_batch = NULL;
-
 
75
    spinlock_initialize(&rcu_global_lock, "rcu_global_lock");
-
 
76
 
-
 
77
    rcu_tasklet_desc = tasklet_register(&rcu_tasklet, NULL);
-
 
78
    tasklet_disable(rcu_tasklet_desc);
-
 
79
 
-
 
80
#ifdef CONFIG_SMP 
-
 
81
    _rcu_global->cpu_mask = malloc (sizeof(bool)*config.cpu_count,0);
-
 
82
    for (i=0;i<config.cpu_count;i++) {
-
 
83
        _rcu_global->cpu_mask[i]=false;
-
 
84
    }
-
 
85
#else
-
 
86
    tasklet_schedule(rcu_tasklet_desc);
-
 
87
 
-
 
88
#endif
-
 
89
    tasklet_enable(rcu_tasklet_desc);
76
}
90
}
77
 
91
 
78
void rcu_synchronize(void)
92
void rcu_synchronize(void)
79
{
93
{
-
 
94
#ifdef CONFIG_SMP
80
    waitq_t wq;
95
    waitq_t *wq = malloc(sizeof(waitq_t),0);
81
    waitq_initialize(&wq);
96
    waitq_initialize(wq);
82
    rcu_sync_callback(rcu_synchronize_callback_function, &wq);
97
    rcu_sync_callback(&rcu_synchronize_callback_function, wq);
-
 
98
    printf("going to sleep\n");
83
    waitq_sleep(&wq);
99
    waitq_sleep(wq);
-
 
100
    printf("woken up\n");
-
 
101
#endif
84
}
102
}
85
 
103
 
-
 
104
#ifdef CONFIG_SMP
86
void rcu_synchronize_callback_function(void* waitq)
105
void rcu_synchronize_callback_function(void* waitq)
87
{
106
{
-
 
107
    printf("waking up\n");
88
    waitq_wakeup(((waitq_t*)waitq), true);
108
    waitq_wakeup(((waitq_t*)waitq), WAKEUP_ALL_INC_MISSED);
89
}
109
}
-
 
110
#endif
90
 
111
 
91
void rcu_sync_callback(void (*func)(void* data), void* data)
112
void rcu_sync_callback(void (*func)(void* data), void* data)
92
{
113
{
-
 
114
#ifndef CONFIG_SMP
-
 
115
    func(data);
-
 
116
#else
93
    int i;
117
    int i;
94
    rcu_callback_list_t *rd;
118
    rcu_callback_list_t *rd;
95
    rd = malloc(sizeof(rcu_callback_list_t), 0);
119
    rd = malloc(sizeof(rcu_callback_list_t), 0);
96
    rd->func = func;
120
    rd->func = func;
97
    rd->data = data;
121
    rd->data = data;
98
    rd->next = NULL;
122
    rd->next = NULL;
-
 
123
    printf("synccallback locking \n");
-
 
124
    spinlock_lock(&rcu_global_lock);
-
 
125
    rd->next = _rcu_global->next_batch;
-
 
126
    _rcu_global->next_batch = rd;
-
 
127
 
-
 
128
    if (_rcu_global->current_batch == NULL) {
-
 
129
        _rcu_global->current_batch = _rcu_global->next_batch;
-
 
130
        _rcu_global->next_batch = NULL;
-
 
131
        printf("setting callback %x as current\n",&rd->func);
-
 
132
        for (i=0;i<config.cpu_count;i++)
-
 
133
            _rcu_global->cpu_mask[i]=false;
99
 
134
 
100
    rd->cpu_mask = malloc (sizeof(bool)*config.cpu_count,0);
135
        //we've surely passed the quiescent point just by running this method
101
    for (i=0;i<config.cpu_count;i++)
-
 
102
        rd->cpu_mask[i]=false;
136
        rcu_passQS();
103
   
137
    }
104
    i = ++(_rcu_global.current_batch);
-
 
105
    _rcu_global.next_batch_waiting = true;
-
 
106
 
-
 
107
    rd->next = _rcu_cpu_lists[0].next_batch;
-
 
108
    for (i=0;i<config.cpu_count;i++) {
138
    for (i=0;i<config.cpu_count;i++) {
-
 
139
        tasklet_schedule_SMP(rcu_tasklet_desc, i);
-
 
140
    }
-
 
141
    spinlock_unlock(&rcu_global_lock);
-
 
142
    printf ("sync callback called,unlocking, state:%x \n",rcu_tasklet_desc->state);
-
 
143
#endif
-
 
144
}
-
 
145
 
-
 
146
    //TODO: polishing, comments
-
 
147
 
-
 
148
void rcu_tasklet(void* data)
-
 
149
{
-
 
150
    rcu_callback_list_t* rd;
-
 
151
    bool passed_all_QS;
-
 
152
#ifdef CONFIG_SMP 
-
 
153
    int i;
-
 
154
#endif
-
 
155
    rcu_passQS();
-
 
156
    passed_all_QS = true;
-
 
157
    printf("tasklet locking \n");
-
 
158
    spinlock_lock(&rcu_global_lock);
-
 
159
#ifdef CONFIG_SMP 
-
 
160
 
-
 
161
    for (i = 0; i < config.cpu_active; i++)
-
 
162
        passed_all_QS &= _rcu_global->cpu_mask[i];
-
 
163
#endif
-
 
164
    if (passed_all_QS) {
109
        _rcu_cpu_lists[i].next_batch = rd;
165
        if (_rcu_global->done_batch) {
-
 
166
            rd = _rcu_global->done_batch;
-
 
167
            while (rd->next) rd = rd->next;
-
 
168
 
-
 
169
            //append the current list to done list
-
 
170
            rd->next = _rcu_global->current_batch;
-
 
171
        } else
-
 
172
            _rcu_global->done_batch = _rcu_global->current_batch;
-
 
173
        printf("setting callback %x as done\n",&_rcu_global->current_batch->func);
110
        _rcu_cpu_lists[i].QS_pending = true;
174
        _rcu_global->current_batch = NULL;
111
    }
175
    }
112
 
176
 
-
 
177
    _rcu_global->current_batch = _rcu_global->next_batch;
-
 
178
    _rcu_global->next_batch = NULL;
-
 
179
 
-
 
180
    if (_rcu_global->current_batch == NULL) {
-
 
181
        //there are no rcu callbacks registered, there is no need to monitor QS 
-
 
182
        printf("tasklet idle disabling \n");
113
    //TODO:tasklet, after_thread_ran, polishing
183
//      tasklet_disable(rcu_tasklet_desc);
-
 
184
        spinlock_unlock(&rcu_global_lock);
-
 
185
    } else
-
 
186
        spinlock_unlock(&rcu_global_lock);
-
 
187
    printf("tasklet unlocking \n");
114
}
188
}
115
 
189
 
-
 
190
inline void rcu_passQS(void)
-
 
191
{
-
 
192
#ifdef CONFIG_SMP 
-
 
193
    _rcu_global->cpu_mask[CPU->id] = true;
-
 
194
#endif
-
 
195
}
-
 
196
 
-
 
197
void rcu_run_callbacks(void)
-
 
198
{
-
 
199
    rcu_callback_list_t* rd;
-
 
200
    rcu_passQS();
-
 
201
    if (_rcu_global->done_batch) {
-
 
202
        printf(".");
-
 
203
        spinlock_lock(&rcu_global_lock);
-
 
204
        for (rd = _rcu_global->done_batch; rd; rd=rd->next) {
-
 
205
            printf("calling %x \n",&rd->func);
-
 
206
            rd->func(&rd->data);
-
 
207
        }
-
 
208
        _rcu_global->done_batch = NULL;
-
 
209
        spinlock_unlock(&rcu_global_lock);
-
 
210
        printf(":");
-
 
211
    }
-
 
212
}
-
 
213
 
-
 
214