1/* 2Copyright (C) 2001-2014, Parrot Foundation. 3 4=head1 NAME 5 6src/pmc/scheduler.pmc - Scheduler PMC 7 8=head1 DESCRIPTION 9 10Access to the core concurrency scheduler. 11 12=head2 Vtable Functions 13 14=over 4 15 16=cut 17 18*/ 19 20#include "parrot/scheduler_private.h" 21 22/* HEADERIZER HFILE: none */ 23/* HEADERIZER BEGIN: static */ 24/* HEADERIZER END: static */ 25 26pmclass Scheduler auto_attrs { 27 ATTR INTVAL id; /* The scheduler's ID. */ 28 ATTR PMC *handlers; /* The list of currently active handlers. */ 29 ATTR PMC *messages; /* A message queue used for communication 30 between schedulers. */ 31 32 ATTR PMC *task_queue; /* List of tasks/green threads waiting to run */ 33 ATTR PMC *foreign_tasks; /* List of tasks/green threads waiting to run */ 34 ATTR Parrot_mutex task_queue_lock; 35 ATTR PMC *alarms; /* List of future alarms ordered by time */ 36 37 ATTR PMC *all_tasks; /* Hash of all active tasks by ID */ 38 ATTR UINTVAL next_task_id; /* ID to assign to the next created task */ 39 40 ATTR Parrot_Interp interp; /* A link to the scheduler's interpreter. */ 41 42/* 43 44=item C<void init()> 45 46Initializes a concurrency scheduler object. 47 48=cut 49 50*/ 51 52 VTABLE void init() { 53 Parrot_Scheduler_attributes * const core_struct = 54 (Parrot_Scheduler_attributes *) PMC_data(SELF); 55 56 /* Set flags for custom GC mark and destroy. */ 57 PObj_custom_mark_SET(SELF); 58 PObj_custom_destroy_SET(SELF); 59 60 /* Set up the core struct. */ 61 core_struct->id = 0; 62 core_struct->next_task_id = 0; 63 core_struct->interp = INTERP; 64 65 /* TODO: Do we need to eagerly create all these PMCs, or can we create 66 them lazily on demand? */ 67 core_struct->handlers = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray); 68 core_struct->messages = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray); 69 core_struct->task_queue = Parrot_pmc_new(INTERP, enum_class_PMCList); 70 core_struct->foreign_tasks = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray); 71 core_struct->alarms = Parrot_pmc_new(INTERP, enum_class_PMCList); 72 core_struct->all_tasks = Parrot_pmc_new(INTERP, enum_class_Hash); 73 74 MUTEX_INIT(core_struct->task_queue_lock); 75 76 /* Chandon TODO: Delete from int-keyed hash doesn't like me. */ 77 /* VTABLE_set_integer_native(interp, core_struct->all_tasks, Hash_key_type_int); */ 78 79 } 80 81/* 82 83=item C<void init_pmc(PMC *data)> 84 85Initializes a new Scheduler with a C<Hash> PMC with any or all of the keys: 86 87=over 4 88 89=item C<id> 90 91An C<Integer> representing the unique identifier for this scheduler. 92 93=back 94 95=cut 96 97*/ 98 99 VTABLE void init_pmc(PMC *data) { 100 PMC *elem; 101 Parrot_Scheduler_attributes *core_struct; 102 103 if (!VTABLE_isa(INTERP, data, CONST_STRING(INTERP, "Hash"))) 104 Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION, 105 "Scheduler initializer must be a Hash"); 106 107 SELF.init(); 108 109 core_struct = PARROT_SCHEDULER(SELF); 110 elem = VTABLE_get_pmc_keyed_str(INTERP, data, CONST_STRING(INTERP, "id")); 111 112 if (!PMC_IS_NULL(elem)) 113 core_struct->id = VTABLE_get_integer(INTERP, elem); 114 } 115 116 117/* 118 119=item C<void push_pmc(PMC *value)> 120 121Inserts a task into the task list. 122 123=cut 124 125*/ 126 127 void push_pmc(PMC *task) { 128 Parrot_Scheduler_attributes * const core_struct = PARROT_SCHEDULER(SELF); 129 130 LOCK(core_struct->task_queue_lock); 131 VTABLE_push_pmc(INTERP, core_struct->task_queue, task); 132 UNLOCK(core_struct->task_queue_lock); 133 } 134 135 136/* 137 138=item C<void unshift_pmc(PMC *value)> 139 140Inserts a task into the head of the task list. 141 142=cut 143 144*/ 145 146 void unshift_pmc(PMC *task) { 147 Parrot_Scheduler_attributes * const core_struct = PARROT_SCHEDULER(SELF); 148 149 LOCK(core_struct->task_queue_lock); 150 VTABLE_unshift_pmc(INTERP, core_struct->task_queue, task); 151 UNLOCK(core_struct->task_queue_lock); 152 } 153 154 155/* 156 157=item C<PMC *shift_pmc()> 158 159Retrieves the next task from the task list. 160 161=cut 162 163*/ 164 165 VTABLE PMC *shift_pmc() { 166 Parrot_Scheduler_attributes * const core_struct = PARROT_SCHEDULER(SELF); 167 PMC * task; 168 169 LOCK(core_struct->task_queue_lock); 170 task = VTABLE_shift_pmc(INTERP, core_struct->task_queue); 171 UNLOCK(core_struct->task_queue_lock); 172 173 return task; 174 } 175 176 177/* 178 179=item C<INTVAL get_integer()> 180 181Retrieves the number of pending tasks in the scheduler's task list. 182 183=cut 184 185*/ 186 187 VTABLE INTVAL get_integer() :no_wb { 188 Parrot_Scheduler_attributes * const core_struct = PARROT_SCHEDULER(SELF); 189 INTVAL elements; 190 191 LOCK(core_struct->task_queue_lock); 192 elements = VTABLE_elements(INTERP, PARROT_SCHEDULER(SELF)->task_queue); 193 UNLOCK(core_struct->task_queue_lock); 194 195 return elements; 196 } 197 198 199/* 200 201=item C<void destroy()> 202 203Frees the scheduler's underlying struct. 204 205=cut 206 207*/ 208 VTABLE void destroy() :no_wb { 209 UNUSED(INTERP) 210 UNUSED(SELF) 211 } 212 213 214/* 215 216=item C<void mark()> 217 218Marks any referenced strings and PMCs as live. 219 220=cut 221 222*/ 223 VTABLE void mark() :no_wb { 224 if (PARROT_SCHEDULER(SELF)) { 225 Parrot_Scheduler_attributes * const core_struct = PARROT_SCHEDULER(SELF); 226 227 Parrot_gc_mark_PMC_alive(INTERP, core_struct->handlers); 228 Parrot_gc_mark_PMC_alive(INTERP, core_struct->messages); 229 Parrot_gc_mark_PMC_alive(INTERP, core_struct->task_queue); 230 Parrot_gc_mark_PMC_alive(INTERP, core_struct->foreign_tasks); 231 Parrot_gc_mark_PMC_alive(INTERP, core_struct->alarms); 232 Parrot_gc_mark_PMC_alive(INTERP, core_struct->all_tasks); 233 } 234 } 235 236 237/* 238 239=item C<void visit(PMC *info)> 240 241Visits the contents of the scheduler (used by freeze/thaw). 242 243C<*info> is the visit info (see F<include/parrot/pmc_freeze.h>). 244 245=cut 246 247*/ 248 249 VTABLE void visit(PMC *info) :no_wb { 250 /* 1) visit task list */ 251 VISIT_PMC_ATTR(INTERP, info, SELF, Scheduler, task_queue); 252 253 /* 2) visit the handlers */ 254 VISIT_PMC_ATTR(INTERP, info, SELF, Scheduler, handlers); 255 256 /* 3) visit the alarms */ 257 VISIT_PMC_ATTR(INTERP, info, SELF, Scheduler, alarms); 258 259 /* 3) visit all tasks */ 260 VISIT_PMC_ATTR(INTERP, info, SELF, Scheduler, all_tasks); 261 } 262 263 264/* 265 266=item C<void freeze(PMC *info)> 267 268Archives the scheduler. 269 270=cut 271 272*/ 273 274 VTABLE void freeze(PMC *info) :no_wb { 275 Parrot_Scheduler_attributes * const core_struct = PARROT_SCHEDULER(SELF); 276 277 /* 1) freeze scheduler id */ 278 VTABLE_push_integer(INTERP, info, core_struct->id); 279 } 280 281/* 282 283=item C<void thaw(PMC *info)> 284 285Unarchives the scheduler. 286 287=cut 288 289*/ 290 291 VTABLE void thaw(PMC *info) { 292 /* 1. thaw scheduler id */ 293 const INTVAL id = VTABLE_shift_integer(INTERP, info); 294 295 /* Allocate the scheduler's core data struct and set custom flags. */ 296 SELF.init(); 297 298 /* Set the scheduler's id to the frozen id */ 299 PARROT_SCHEDULER(SELF)->id = id; 300 } 301 302 303/* 304 305=item C<void thawfinish(PMC *info)> 306 307Finishes thawing the scheduler. 308 309=cut 310 311*/ 312 313 VTABLE void thawfinish(PMC *info) :no_wb { 314 UNUSED(info) 315 UNUSED(INTERP) 316 UNUSED(SELF) 317 /* Parrot_cx_refresh_task_list(INTERP, SELF); */ 318 } 319 320 321/* 322 323=back 324 325=head2 Methods 326 327=over 4 328 329=cut 330 331*/ 332 333/* 334 335=item C<METHOD active_tasks()> 336 337Returns a ResizablePMCArray containing pointers to all active tasks. 338 339=cut 340 341*/ 342 343 METHOD active_tasks() { 344 Parrot_Scheduler_attributes *sdata = PARROT_SCHEDULER(SELF); 345 PMC * const tasks = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray); 346 PMC * const iter = Parrot_pmc_new_init(INTERP, enum_class_HashIterator, sdata->all_tasks); 347 348 while (!VTABLE_get_bool(INTERP, iter)) { 349 PMC * const pair = VTABLE_shift_pmc(INTERP, iter); 350 PMC * task = PMCNULL; 351 STRING * const value = CONST_STRING(INTERP, "value"); 352 Parrot_pcc_invoke_method_from_c_args(INTERP, pair, 353 value, "->P", &task); 354 VTABLE_push_pmc(INTERP, tasks, task); 355 } 356 357 RETURN(PMC* tasks); 358 } 359} 360 361/* 362 363=back 364 365=head1 SEE ALSO 366 367F<docs/pdds/pdd25_concurrency.pod>. 368 369=cut 370 371*/ 372 373/* 374 * Local variables: 375 * c-file-style: "parrot" 376 * End: 377 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' : 378 */ 379