Project

General

Profile

Statistics
| Revision:

root / branches / simulator / projects / simulator / simulator / core / robot.c @ 1010

History | View | Annotate | Download (5.06 KB)

1
/**
2
 * @file robot.c
3
 * @author Colony Project
4
 * @brief Simulator Robot Management
5
 *
6
 * Contains implementations of functions managing robots
7
 * in the simulator, including process control and memory
8
 * management.
9
 **/
10

    
11
#include <stdlib.h>
12
#include <stdio.h>
13
#include <string.h>
14

    
15
#include <unistd.h>
16
#include <signal.h>
17
#include <sys/wait.h>
18
#include <robot_shared.h>
19
#include <sys/ipc.h>
20
#include <sys/types.h>
21
#include <sys/shm.h>
22
#include <errno.h>
23
#include <pthread.h>
24

    
25
#include "robot.h"
26
#include "motion.h"
27
#include "gtk_gui.h"
28

    
29
void sig_chld_handler(int sig);
30
void robot_update(int i);
31

    
32
// global variables
33
int first_available_id = 0;
34
// an expanding array of robots
35
Robot* robots = NULL;
36
int robots_size = 0;
37
int num_robots = 0;
38

    
39
int iterator_pos = 0;
40

    
41
// signalled when all robots have run for a bit
42
pthread_mutex_t all_finished_mutex;
43
pthread_cond_t all_finished_cond;
44
int finished = 0;
45

    
46
int robots_initialize(void)
47
{
48
        int i;
49
        if (signal(SIGCHLD, sig_chld_handler) == SIG_ERR)
50
                return -1;
51

    
52
        robots_size = 10;
53
        robots = (Robot*)malloc(sizeof(Robot) * robots_size);
54
        if (!robots)
55
                return -1;
56
        memset(robots, 0, sizeof(Robot) * robots_size);
57
        for (i = 0; i < robots_size; i++)
58
                robots[i].id = -1;
59
        
60
        finished = 0;
61
        pthread_mutex_init(&all_finished_mutex, NULL);
62
        pthread_cond_init(&all_finished_cond, NULL);
63

    
64
        return 0;
65
}
66

    
67
/**
68
 * Creates a new robot. Returns its id on
69
 * success, or a negative integer on failure.
70
 **/
71
int robot_create(char *execname)
72
{
73
        int pid;
74
        int id = first_available_id;
75
        Robot* r = &robots[id];
76
        printf("ID: %d\n", id);
77
        // do shared memory stuff here
78
        key_t key = IPC_PRIVATE;
79
        //Memory accessible only to children with r/w privileges
80
        r->sharedMemID = shmget(key, sizeof(RobotShared), IPC_CREAT | 0666);
81
        
82
        if(r->sharedMemID < 0)
83
        {
84
                fprintf(stderr, "Failed to get shared memory.\n");
85
                return -1;
86
        }
87

    
88
        r->shared = (RobotShared*)shmat(r->sharedMemID, NULL, 0);
89
        
90
        if(!(r->shared))
91
        {        
92
                //Free shared memory region
93
                if (!shmctl(r->sharedMemID, IPC_RMID, NULL))
94
                        fprintf(stderr, "Failed to free shared memory.\n");
95
                       
96
                fprintf(stderr, "Error attaching memory to parent.\n");
97
                return -1;
98
        }
99
        
100
        // Initialize robot structure here
101
        r->shared->motor1 = 0;
102
        r->shared->motor2 = 0;
103
        r->id = id;
104

    
105
        if((pid = fork()) < 0)
106
        {
107
                //Free Shared Memory Region
108
                if (!shmdt(r->shared))
109
                        fprintf(stderr, "Failed to free shared memory.\n");
110
                
111
                if (!shmctl(r->sharedMemID, IPC_RMID, NULL))
112
                        fprintf(stderr, "Failed to free shared memory.\n");
113

    
114
                r->id = -1;
115
                fprintf(stderr, "Failed to fork robot process.\n");
116
                return -1;
117
        }
118
        
119

    
120
        if(!pid)
121
        {
122
          char var[21];
123
          /* restore default sigchld handler */
124
          signal(SIGCHLD, SIG_DFL);
125
          sprintf(var, "memory_id=%d", r->sharedMemID);
126
          putenv(var);
127
          //TODO: keep the other env. stuff around
128
          execv(execname, NULL);
129
          fprintf(stderr, "exec failed to run child process.\n");
130
          exit(-1);
131
        }
132
        else
133
        {
134
                r->pid = pid;
135
                do {
136
                        first_available_id++;
137
                } while (first_available_id < robots_size &&
138
                                robots[first_available_id].id != -1);
139
                // resize the array if necessary
140
                if (first_available_id >= robots_size)
141
                {
142
                        robots_size *= 2;
143
                        robots = realloc(robots, sizeof(Robot) * robots_size);
144
                        if (!robots)
145
                        {
146
                                fprintf(stderr, "Out of memory.\n");
147
                                return -1;
148
                        }
149
                }
150
        }
151

    
152
        num_robots++;
153
        
154
        return id;
155
}
156

    
157
/**
158
 * Frees all resources associated with a robot, including
159
 * killing its process if necessary.
160
 *
161
 * @return zero on success, nonzero on failure
162
 **/
163
int robot_destroy(int id)
164
{
165
        Robot* r;
166

    
167
        if (id < 0 || id >= robots_size)
168
                return -1;
169
        r = &robots[id];
170
        if (r->id == 0)
171
                return -1;
172

    
173
    if (!shmdt(r->shared))
174
        {
175
                fprintf(stderr, "Failed to free shared memory.\n");
176
                return -1;
177
        }
178
        if (!shmctl(r->sharedMemID, IPC_RMID, NULL))
179
        {
180
                fprintf(stderr, "Failed to free shared memory.\n");
181
                return -1;
182
        }
183

    
184
        memset(r, 0, sizeof(Robot));
185
        r->id = -1;
186

    
187
        if (id < first_available_id)
188
                first_available_id = 0;
189
        
190
        return 0;
191
}
192

    
193
void robot_iterator_reset(void)
194
{
195
        iterator_pos = -1;
196
}
197

    
198
// note: addresses may change, replace with
199
// allocated memory
200
Robot* robot_iterator_next(void)
201
{
202
        if (iterator_pos >= robots_size)
203
                return NULL;
204
        do iterator_pos++;
205
        while (iterator_pos < robots_size && 
206
                        robots[iterator_pos].id == -1);
207
        
208
        if (iterator_pos >= robots_size)
209
                return NULL;
210
        
211
        return &(robots[iterator_pos]);
212
}
213

    
214
void sig_chld_handler(int sig)
215
{
216
        pthread_mutex_lock(&all_finished_mutex);
217
        finished++;
218
        if (finished >= num_robots)
219
        {
220
                pthread_cond_signal(&all_finished_cond);
221
        }
222
        pthread_mutex_unlock(&all_finished_mutex);
223
}
224

    
225
void* robot_event_loop(void* arg)
226
{
227
        int i;
228
        //TODO: errors
229

    
230
        while (1)
231
        {
232
                pthread_mutex_lock(&all_finished_mutex);
233
                // TODO: race condition for adding robots?
234
                if (finished < num_robots)
235
                {
236
                        pthread_cond_wait(&all_finished_cond, &all_finished_mutex);
237
                }
238
                finished = 0;
239
                pthread_mutex_unlock(&all_finished_mutex);
240
                for (i = 0; i < robots_size; i++)
241
                        if (robots[i].id != -1)
242
                                robot_update(i);
243
                for (i = 0; i < robots_size; i++)
244
                {
245
                        if (robots[i].id == -1)
246
                                continue;
247
                        kill(robots[i].pid, SIGCONT);
248
                }
249

    
250
                gui_refresh();
251
        }
252
}
253

    
254
void robot_update(int i)
255
{
256
        Robot* r = &(robots[i]);
257
        if (r->id == -1)
258
                return;
259
        move_robot(r);
260
}
261