Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (7.46 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
#include <err.h>
25
#include <unistd.h>
26

    
27
#include "gtk_gui.h"
28

    
29
#include "robot.h"
30
#include "motion.h"
31
#include "rangefinders.h"
32
#include "world.h"
33
#include "logger.h"
34
#include "gtk_gui.h"
35

    
36

    
37
void sig_chld_handler(int sig);
38
void robot_update(int i);
39

    
40
// global variables
41
int first_available_id = 0;
42
// an expanding array of robots
43
Robot* robots = NULL;
44
int robots_size = 0;
45
int num_robots = 0;
46

    
47
int iterator_pos = 0;
48

    
49
int timeStep = 0;
50

    
51
// signalled when all robots have run for a bit
52
pthread_mutex_t all_finished_mutex;
53
pthread_cond_t all_finished_cond;
54
int finished = 0;
55

    
56
int pausing = 0;
57
int paused = 0;
58

    
59
int robots_initialize(void)
60
{
61
        int i;
62
        if (signal(SIGCHLD, sig_chld_handler) == SIG_ERR)
63
                return -1;
64

    
65
        robots_size = 10;
66
        robots = (Robot*)malloc(sizeof(Robot) * robots_size);
67
        if (!robots)
68
                return -1;
69
        memset(robots, 0, sizeof(Robot) * robots_size);
70
        for (i = 0; i < robots_size; i++)
71
                robots[i].id = -1;
72

    
73
        finished = 0;
74
        pthread_mutex_init(&all_finished_mutex, NULL);
75
        pthread_cond_init(&all_finished_cond, NULL);
76

    
77
        return 0;
78
}
79

    
80
int robots_cleanup(void)
81
{
82
        robots_pause();
83
        //TODO: clean things up
84
        return 0;
85
}
86

    
87
void robots_pause(void)
88
{
89
        pausing = 1;
90
        while (!paused) usleep(10000);
91
}
92

    
93
void robots_resume(void)
94
{
95
        pausing = 0;
96
}
97

    
98
/**
99
 * Creates a new robot. Returns its id on
100
 * success, or a negative integer on failure.
101
 **/
102
int robot_create(char *execname)
103
{
104
          int pid,i;
105
        int id = first_available_id;
106
        Robot* r = &robots[id];
107
        // do shared memory stuff here
108
        key_t key = IPC_PRIVATE;
109
        //Memory accessible only to children with r/w privileges
110
        r->sharedMemID = shmget(key, sizeof(RobotShared), IPC_CREAT | 0666);
111

    
112

    
113
        //hack!! TODO: remove!!
114
        r->pose.x=first_available_id*100;
115
        r->pose.y=first_available_id*50;
116

    
117

    
118
        if(r->sharedMemID < 0)
119
        {
120
                fprintf(stderr, "Failed to get shared memory.\n");
121
                return -1;
122
        }
123

    
124
        r->shared = (RobotShared*)shmat(r->sharedMemID, NULL, 0);
125

    
126
        if(!(r->shared))
127
        {
128
                //Free shared memory region
129
                if (!shmctl(r->sharedMemID, IPC_RMID, NULL))
130
                        fprintf(stderr, "Failed to free shared memory.\n");
131

    
132
                fprintf(stderr, "Error attaching memory to parent.\n");
133
                return -1;
134
        }
135

    
136
        // Initialize robot structure here
137
        r->shared->motor1 = 0;
138
        r->shared->motor2 = 0;
139
        r->id = id;
140

    
141
        if(execname != NULL)
142
        {
143
                if((pid = fork()) < 0)
144
                {
145
                        //Free Shared Memory Region
146
                        if (!shmdt(r->shared))
147
                                fprintf(stderr, "Failed to free shared memory.\n");
148

    
149
                        if (!shmctl(r->sharedMemID, IPC_RMID, NULL))
150
                                fprintf(stderr, "Failed to free shared memory.\n");
151

    
152
                        r->id = -1;
153
                        fprintf(stderr, "Failed to fork robot process.\n");
154
                        return -1;
155
                }
156
        }
157

    
158

    
159
        if(!pid && execname)
160
        {
161
          char var[21];
162
          /* restore default sigchld handler */
163
          signal(SIGCHLD, SIG_DFL);
164
          sprintf(var, "memory_id=%d", r->sharedMemID);
165
          putenv(var);
166
          //TODO: keep the other env. stuff around
167
          execv(execname, NULL);
168
          err(errno, "exec failed to run child process.\n");
169
        }
170
        else
171
        {
172
                r->pid = pid;
173
                do {
174
                        first_available_id++;
175
                } while (first_available_id < robots_size &&
176
                                robots[first_available_id].id != -1);
177
                // resize the array if necessary
178
                if (first_available_id >= robots_size)
179
                {
180
                        robots_size *= 2;
181
                        robots = realloc(robots, sizeof(Robot) * robots_size);
182
                        if (!robots)
183
                        {
184
                                fprintf(stderr, "Out of memory.\n");
185
                                return -1;
186
                        }
187
                        for (i = robots_size=first_available_id; i < robots_size; i++)
188
                          robots[i].id = -1;
189

    
190
                }
191
        }
192

    
193
        //Log creation
194
        if(execname != NULL)
195
        {
196
                //printf("commiting %d\n", num_robots);
197
                commit(r, num_robots, CREATE_STEP);
198
        }
199
        num_robots++;
200

    
201
        return id;
202
}
203

    
204
/**
205
 * Frees all resources associated with a robot, including
206
 * killing its process if necessary.
207
 *
208
 * @return zero on success, nonzero on failure
209
 **/
210
int robot_destroy(int id)
211
{
212
        Robot* r;
213

    
214
        if (id < 0 || id >= robots_size)
215
                return -1;
216
        r = &robots[id];
217
        if (r->id == 0)
218
                return -1;
219

    
220
    if (!shmdt(r->shared))
221
        {
222
                fprintf(stderr, "Failed to free shared memory.\n");
223
                return -1;
224
        }
225
        if (!shmctl(r->sharedMemID, IPC_RMID, NULL))
226
        {
227
                fprintf(stderr, "Failed to free shared memory.\n");
228
                return -1;
229
        }
230

    
231
        memset(r, 0, sizeof(Robot));
232
        r->id = -1;
233

    
234
        if (id < first_available_id)
235
                first_available_id = 0;
236

    
237

    
238
        return 0;
239
}
240

    
241
void robot_destroy_all()
242
{
243
        int i;
244
        for(i = 0; i < num_robots; i++)
245
                robot_destroy(i);
246
}
247

    
248
void robot_iterator_reset(void)
249
{
250
        iterator_pos = -1;
251
}
252

    
253
// note: addresses may change, replace with
254
// allocated memory
255
Robot* robot_iterator_next(void)
256
{
257
        if (iterator_pos >= robots_size)
258
                return NULL;
259
        do iterator_pos++;
260
        while (iterator_pos < robots_size &&
261
                        robots[iterator_pos].id == -1);
262

    
263
        if (iterator_pos >= robots_size)
264
                return NULL;
265

    
266
        return &(robots[iterator_pos]);
267
}
268

    
269
void sig_chld_handler(int sig)
270
{
271
  int ret,stat;
272

    
273
  pthread_mutex_lock(&all_finished_mutex);
274

    
275
  while((ret = waitpid(-1, &stat, WUNTRACED | WNOHANG)))
276
  {
277
    if(ret==-1)
278
      err(errno,"error waiting on robot");
279

    
280
    if(WIFSTOPPED(stat))
281
      finished++;
282
  }
283

    
284
  if (finished >= num_robots)
285
  {
286
    pthread_cond_signal(&all_finished_cond);
287
  }
288
  pthread_mutex_unlock(&all_finished_mutex);
289
}
290

    
291
void* robot_event_loop(void* arg)
292
{
293
        int i;
294
        int ret;
295

    
296
        //TODO: not exit if there is an error?
297

    
298
        while (1)
299
        {
300
                ret = pthread_mutex_lock(&all_finished_mutex);
301
                if(ret)
302
                  err(errno, "error locking mutex in even loop");
303
                // TODO: race condition for adding robots?
304
                if (finished < num_robots)
305
                {
306
                        ret = pthread_cond_wait(&all_finished_cond, &all_finished_mutex);
307
                        if(ret)
308
                          err(errno, "error waiting on condition variable");
309
                }
310
                finished = 0;
311
                
312
                ret = pthread_mutex_unlock(&all_finished_mutex);
313

    
314
                //sleep to avoid 100% CPU usage
315
                usleep(10000);
316
                while (pausing)
317
                {
318
                        paused = 1;
319
                        usleep(50000);
320
                }
321
                paused = 0;
322

    
323
                if(ret)
324
                  fprintf(stderr, "hmmm, error unlocking. errno: %d", errno);
325

    
326
                timeStep++;
327
                for (i = 0; i < robots_size; i++)
328
                        if (robots[i].id != -1)
329
                        {
330
                                robot_update(i);
331

    
332
                                commit(&robots[i],i,timeStep);
333
                        }
334
                for (i = 0; i < robots_size; i++)
335
                {
336
                        if (robots[i].id == -1)
337
                                continue;
338
                        ret = kill(robots[i].pid, SIGCONT);
339
                        if(ret)
340
                          warn("error: could not kill resume robot proc.");
341
                }
342

    
343
                if (timeStep % 5 == 0)
344
                        gui_refresh();
345
        }
346
}
347

    
348
void* logger_step_loop(void* arg)
349
{
350
        printf("going into logger\n");
351
        int timeStep;
352
        int index;
353

    
354
        int prevStep = -1;
355

    
356
        if(fread(&timeStep, sizeof(int), 1, file) < 1)
357
        {
358
                robot_destroy_all();
359
                fprintf(stderr, "problem reading timestep\n");
360

    
361
            return (void*)-1;
362
        }
363

    
364
         while(1){
365
                prevStep = timeStep;
366
                do
367
                   {
368
                        if(fread(&index, sizeof(int), 1, file) < 1)
369
                        {
370
                                robot_destroy_all();
371
                                 return (void*) -1;
372
                        }
373

    
374
            //Update the robot
375
                        if(timeStep == CREATE_STEP)
376
                        {
377
                            robot_create(NULL);
378
                        }
379

    
380

    
381
                        if(getLog(&robots[index]) < 0)
382
                        {
383
                                robot_destroy_all();
384
                                 return (void*) -1;
385
                        }
386

    
387
                        //Read in next logfile and check number
388
                           if(fread(&timeStep, sizeof(int), 1, file) < 1)
389
                        {
390
                                robot_destroy_all();
391
                                return (void*)-1;
392
                        }
393

    
394
                   if (prevStep < 0)
395
                                   prevStep = timeStep;
396
                   }while(timeStep == prevStep || timeStep == CREATE_STEP);
397

    
398

    
399
                gui_refresh();
400

    
401
                usleep(100);
402
        }
403

    
404
}
405

    
406
void robot_update(int i)
407
{
408
        Robot* r = &(robots[i]);
409
        if (r->id == -1)
410
                return;
411
        move_robot(r);
412
        update_rangefinders(r);
413
}
414