1 #include "shotgun/lib/shotgun.h"
2 #include "shotgun/lib/cpu.h"
3 #include "shotgun/lib/environment.h"
4 #include "shotgun/lib/config_hash.h"
5 #include "shotgun/lib/symbol.h"
6 #include "shotgun/lib/tuple.h"
13 static pthread_key_t global_key
;
15 #define lock(e) pthread_mutex_lock(&e->mutex)
16 #define unlock(e) pthread_mutex_unlock(&e->mutex)
18 void environment_at_startup() {
19 pthread_key_create(&global_key
, NULL
);
22 static void _find_child_waiters(int key
, void *mach
) {
24 cpu_find_waiters(m
->s
);
28 static void _child_ev_cb(EV_P_
struct ev_signal
*w
, int revents
) {
29 environment e
= (environment
)w
->data
;
31 // call for all VMs/states
32 ht_vconfig_each(e
->machines
, _find_child_waiters
);
35 environment
environment_new() {
36 environment e
= ALLOC_N(struct rubinius_environment
, 1);
37 e
->machines
= ht_vconfig_create(11);
40 e
->messages
= ht_vconfig_create(11);
41 e
->sig_event_base
= ev_default_loop(EVFLAG_FORKCHECK
);
45 static void _fork_event_loops(int key
, void *mach
) {
47 ev_loop_fork(m
->s
->event_base
);
48 ev_loop(m
->s
->event_base
, EVLOOP_NONBLOCK
);
51 void environment_fork() {
52 environment e
= environment_current();
55 ev_loop(e
->sig_event_base
, EVLOOP_NONBLOCK
);
56 ht_vconfig_each(e
->machines
, _fork_event_loops
);
59 void environment_setup_thread(environment e
, machine m
) {
60 struct rubinius_global
*global
= ALLOC_N(struct rubinius_global
, 1);
65 pthread_setspecific(global_key
, (const void*)global
);
67 ev_signal_init(&e
->sig_ev
, _child_ev_cb
, SIGCHLD
);
69 ev_signal_start(e
->sig_event_base
, &e
->sig_ev
);
72 environment
environment_current() {
73 struct rubinius_global
*global
;
74 global
= (struct rubinius_global
*)pthread_getspecific(global_key
);
78 machine
environment_current_machine() {
79 struct rubinius_global
*global
;
80 global
= (struct rubinius_global
*)pthread_getspecific(global_key
);
81 if(!global
) return NULL
;
85 void environment_add_machine(environment e
, machine m
) {
89 m
->pthread
= pthread_self();
90 m
->id
= e
->machine_id
++;
92 key
= ALLOC_N(int, 1);
95 ht_vconfig_insert(e
->machines
, key
, (void*)m
);
99 int environment_del_machine(environment e
, machine m
) {
103 old
= ht_vconfig_remove(e
->machines
, &m
->id
);
110 int environment_join_machine(environment e
, int id
) {
115 m
= ht_vconfig_search(e
->machines
, &id
);
120 if(pthread_join(m
->pthread
, &ret
) == 0) {
128 void environment_exit_machine() {
129 machine m
= environment_current_machine();
130 environment e
= environment_current();
136 environment_send_message(e
, m
->parent_id
,
137 tuple_new2(state
, 2, SYM("machine_exited"), I2N(m
->id
)));
143 int environment_load_machine(environment e
, machine m
) {
144 if(e
->platform_config
) {
145 machine_parse_config_file(m
, e
->platform_config
);
148 machine_migrate_config(m
);
150 if(m
->s
->excessive_tracing
) {
151 printf("[ Loading bootstrap bundle %s]\n", e
->bootstrap_path
);
154 if(!machine_load_bundle(m
, e
->bootstrap_path
)) {
155 printf("Problem encountered while loading bootstrap %s\n", e
->bootstrap_path
);
159 if(m
->s
->excessive_tracing
) {
160 printf("[ Loading platform bundle %s]\n", e
->platform_path
);
163 if(!machine_load_bundle(m
, e
->platform_path
)) {
164 printf("Problem encountered while loading platform %s\n", e
->platform_path
);
168 if(m
->s
->excessive_tracing
) {
169 printf("[ Loading core bundle %s]\n", e
->core_path
);
172 if(!machine_load_bundle(m
, e
->core_path
)) {
173 printf("Problem encountered while loading core %s\n", e
->core_path
);
177 if(!machine_run_file(m
, e
->loader_path
)) {
178 printf("Unclean exit from %s\n", e
->core_path
);
185 /* NOTE: this duplicates rubinius_global from environment.h */
191 void *_environment_spawn(void *input
) {
193 struct thread_args
*args
= (struct thread_args
*)input
;
195 environment_setup_thread(args
->e
, args
->m
);
197 /* For now, we mask all signals except VTALRM in sub machines. */
199 //sigdelset(&set, SIGVTALRM);
200 pthread_sigmask(SIG_SETMASK
, &set
, NULL
);
202 environment_load_machine(args
->e
, args
->m
);
207 void environment_start_thread(environment e
, machine m
) {
208 struct thread_args
*args
= ALLOC_N(struct thread_args
, 1);
213 pthread_create(&m
->pthread
, NULL
, _environment_spawn
, (void*)args
);
216 static const char magic
[] = "!";
218 void environment_send_message(environment e
, int id
, OBJECT msg
) {
224 /* Marshal the data before the lock. */
225 m
= environment_current_machine();
226 data
= cpu_marshal_to_bstring(m
->s
, msg
, 0);
230 cur
= ht_vconfig_search(e
->messages
, &id
);
232 cur
= ptr_array_new(8);
233 key
= ALLOC_N(int, 1);
235 ht_vconfig_insert(e
->messages
, key
, cur
);
238 ptr_array_append(cur
, (xpointer
)data
);
240 m
= ht_vconfig_search(e
->machines
, &id
);
242 /* write the magic byte, to let the machine know there are
243 * messages for it. */
244 write(m
->message_write_fd
, magic
, 1);
249 OBJECT
environment_get_message(environment e
, int id
) {
256 cur
= ht_vconfig_search(e
->messages
, &id
);
258 if(ptr_array_length(cur
) == 0) goto error
;
259 data
= ptr_array_remove_index_ordered(cur
, 0);
260 if(!data
) goto error
;
262 /* Now that we're sure we've got what we need, we unlock.. */
266 m
= environment_current_machine();
267 return cpu_unmarshal(m
->s
, (uint8_t*)bdata(data
), (int)blength(data
), 0);