3 /* a fast and simple context switching library */
5 /* Copyright (c) 2004 Arnaud Legrand. All rights reserved. */
7 /* This program is free software; you can redistribute it and/or modify it
8 * under the terms of the license (GNU LGPL) which comes with this package. */
10 #include "context_private.h"
11 #include "xbt/error.h"
12 #include "xbt/dynar.h"
13 #include "gras_config.h"
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(context, xbt, "Context");
17 /************************ GNU LIBC CONTEXTS **************************/
20 static context_t current_context = NULL;
21 static xbt_dynar_t context_to_destroy = NULL;
23 void context_init(void)
25 if(!current_context) {
26 current_context = xbt_new0(s_context_t,1);
27 context_to_destroy = xbt_dynar_new(sizeof(context_t),xbt_free);
31 void context_empty_trash(void)
33 xbt_dynar_reset(context_to_destroy);
36 static void *__context_wrapper(void *c)
38 context_t context = c;
41 /* msg_global->current_process = process; */
43 /* WARNING("Calling the main function"); */
44 (context->code) (context->argc,context->argv);
46 for(i=0;i<context->argc; i++)
47 if(context->argv[i]) xbt_free(context->argv[i]);
48 if(context->argv) xbt_free(context->argv);
50 xbt_dynar_push(context_to_destroy, &context);
52 context_yield(context);
57 void context_start(context_t context)
60 /* TBX_FIFO_insert(msg_global->process, process); */
61 /* TBX_FIFO_insert(msg_global->process_to_run, process); */
63 /* WARNING("Assigning __MSG_process_launcher to context (%p)",context); */
64 makecontext (&(context->uc), (void (*) (void)) __context_wrapper,
70 context_t context_create(context_function_t code,
71 int argc, char *argv[])
75 res = xbt_new0(s_context_t,1);
77 /* WARNING("Initializing context (%p)",res); */
79 xbt_assert0(getcontext(&(res->uc))==0,"Error in context saving.");
83 res->uc.uc_link = &(current_context->uc); /* FIXME LATER */
84 /* WARNING : when this context is over, the current_context (i.e. the
85 father), is awaken... May result in bugs later.*/
86 res->uc.uc_stack.ss_sp = res->stack;
87 res->uc.uc_stack.ss_size = STACK_SIZE;
91 static void context_destroy(context_t context)
98 void context_yield(context_t context)
101 xbt_assert0(current_context,"You have to call context_init() first.");
103 /* __MSG_context_init(); */
104 /* fprintf(stderr,"\n"); */
105 /* WARNING("--------- current_context (%p) is yielding to context(%p) ---------",current_context,context); */
106 /* VOIRP(current_context); */
107 /* if(current_context) VOIRP(current_context->save); */
108 /* VOIRP(context); */
109 /* if(context) VOIRP(context->save); */
112 /* m_process_t self = msg_global->current_process; */
113 if(context->save==NULL) {
114 /* WARNING("**** Yielding to somebody else ****"); */
115 /* WARNING("Saving current_context value (%p) to context(%p)->save",current_context,context); */
116 context->save = current_context ;
117 context->uc.uc_link = &(current_context->uc);
118 /* WARNING("current_context becomes context(%p) ",context); */
119 current_context = context ;
120 /* WARNING("Current position memorized (context->save). Jumping to context (%p)",context); */
121 if(!swapcontext (&(context->save->uc), &(context->uc)))
122 xbt_assert0(0,"Context swapping failure");
123 /* WARNING("I am (%p). Coming back\n",context); */
125 context_t old_context = context->save ;
126 /* WARNING("**** Back ! ****"); */
127 /* WARNING("Setting current_context (%p) to context(%p)->save",current_context,context); */
128 current_context = context->save ;
129 /* WARNING("Setting context(%p)->save to NULL",current_context,context); */
130 context->save = NULL ;
131 /* WARNING("Current position memorized (%p). Jumping to context (%p)",context,old_context); */
132 if(!swapcontext (&(context->uc), &(old_context->uc)) )
133 xbt_assert0(0,"Context swapping failure");
134 /* WARNING("I am (%p). Coming back\n",context); */
136 /* msg_global->current_process = self; */
143 /****************************** PTHREADS ***************************/
144 /* #if HAVE_LIBPTHREAD==1 */
145 #ifdef HAVE_LIBPTHREAD /* Nevermind, let's use pthreads... */
147 static void *__MSG_process_launcher(void *p)
149 m_process_t process = (m_process_t) p;
150 sim_data_process_t sim_data = process->simdata;
151 context_t context = NULL;
153 msg_global->current_process = process;
154 TBX_FIFO_insert(msg_global->process, process);
156 TBX_FIFO_insert(msg_global->process_to_run, process);
157 /* pthread_mutex_lock(&(sim_data->context->mutex)); */
158 __MSG_context_yield(sim_data->context);
160 (*sim_data->context->code) (sim_data->argc,sim_data->argv);
162 TBX_FIFO_remove(msg_global->process, process);
163 TBX_FIFO_remove(msg_global->process_to_run, process);
165 /* Free blocked process if any */
166 /* pthread_mutex_lock(&(sim_data->context->mutex)); */
167 /* pthread_cond_signal(&(sim_data->context->cond)); */
168 /* pthread_mutex_unlock(&(sim_data->context->mutex)); */
170 context = sim_data->context;
172 for(i=0;i<sim_data->argc; i++)
173 if(sim_data->argv[i]) FREE(sim_data->argv[i]);
174 if(sim_data->argv) FREE(sim_data->argv);
175 if(process->name) FREE(process->name);
179 TBX_FIFO_insert(msg_global->context_to_destroy,context);
180 __MSG_context_yield(context);
181 /* __MSG_context_destroy(&context); */
186 MSG_error_t __MSG_context_start(m_process_t process)
188 sim_data_process_t sim_data = NULL;
190 sim_data = process->simdata;
192 pthread_mutex_lock(&(sim_data->context->mutex));
194 /* Launch the thread */
195 if (pthread_create(sim_data->context->thread, NULL, __MSG_process_launcher,
197 WARNING("Unable to create a thread.");
200 pthread_cond_wait(&(sim_data->context->cond), &(sim_data->context->mutex));
201 pthread_mutex_unlock(&(sim_data->context->mutex));
202 /* __MSG_context_yield(sim_data->context); */
207 context_t __MSG_context_create(m_process_code_t code)
209 context_t res = NULL;
211 res = CALLOC(1, sizeof(struct s_context));
214 res->thread = CALLOC(1, sizeof(pthread_t));
215 if (pthread_mutex_init(&(res->mutex), NULL) != 0)
216 FAILURE("Mutex initialization error");
217 if (pthread_cond_init(&(res->cond), NULL) != 0)
218 FAILURE("Condition initialization error");
223 MSG_error_t __MSG_context_destroy(context_t * context)
225 ASSERT(((context != NULL) && (*context != NULL)), "Invalid parameters");
227 FREE((*context)->thread);
228 pthread_mutex_destroy(&((*context)->mutex));
229 pthread_cond_destroy(&((*context)->cond));
237 MSG_error_t __MSG_context_yield(context_t context)
240 m_process_t self = msg_global->current_process;
241 pthread_mutex_lock(&(context->mutex));
242 pthread_cond_signal(&context->cond);
243 pthread_cond_wait(&context->cond, &context->mutex);
244 pthread_mutex_unlock(&(context->mutex));
245 msg_global->current_process = self;
249 #endif /* HAVE_LIBPTHREAD */
250 #endif /* USE_CONTEXT */