Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (5.79 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

    
26
#include "gtk_gui.h"
27

    
28
#include "robot.h"
29
#include "motion.h"
30
#include "rangefinders.h"
31
#include "world.h"
32

    
33
void sig_chld_handler(int sig);
34
void robot_update(int i);
35

    
36
// global variables
37
int first_available_id = 0;
38
// an expanding array of robots
39
Robot* robots = NULL;
40
int robots_size = 0;
41
int num_robots = 0;
42

    
43
int iterator_pos = 0;
44

    
45
// signalled when all robots have run for a bit
46
pthread_mutex_t all_finished_mutex;
47
pthread_cond_t all_finished_cond;
48
int finished = 0;
49

    
50
int robots_initialize(void)
51
{
52
        int i;
53
        if (signal(SIGCHLD, sig_chld_handler) == SIG_ERR)
54
                return -1;
55

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

    
68
        return 0;
69
}
70

    
71
/**
72
 * Creates a new robot. Returns its id on
73
 * success, or a negative integer on failure.
74
 **/
75
int robot_create(char *execname)
76
{
77
  int pid,i;
78
        int id = first_available_id;
79
        Robot* r = &robots[id];
80
        // do shared memory stuff here
81
        key_t key = IPC_PRIVATE;
82
        //Memory accessible only to children with r/w privileges
83
        r->sharedMemID = shmget(key, sizeof(RobotShared), IPC_CREAT | 0666);
84
        
85

    
86
        //hack!! TODO: remove!!
87
        r->pose.x=first_available_id*100;
88
        r->pose.y=first_available_id*50;
89

    
90

    
91
        if(r->sharedMemID < 0)
92
        {
93
                fprintf(stderr, "Failed to get shared memory.\n");
94
                return -1;
95
        }
96

    
97
        r->shared = (RobotShared*)shmat(r->sharedMemID, NULL, 0);
98
        
99
        if(!(r->shared))
100
        {        
101
                //Free shared memory region
102
                if (!shmctl(r->sharedMemID, IPC_RMID, NULL))
103
                        fprintf(stderr, "Failed to free shared memory.\n");
104
                       
105
                fprintf(stderr, "Error attaching memory to parent.\n");
106
                return -1;
107
        }
108
        
109
        // Initialize robot structure here
110
        r->shared->motor1 = 0;
111
        r->shared->motor2 = 0;
112
        r->id = id;
113

    
114
        if((pid = fork()) < 0)
115
        {
116
                //Free Shared Memory Region
117
                if (!shmdt(r->shared))
118
                        fprintf(stderr, "Failed to free shared memory.\n");
119
                
120
                if (!shmctl(r->sharedMemID, IPC_RMID, NULL))
121
                        fprintf(stderr, "Failed to free shared memory.\n");
122

    
123
                r->id = -1;
124
                fprintf(stderr, "Failed to fork robot process.\n");
125
                return -1;
126
        }
127
        
128

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

    
160
                }
161
        }
162

    
163
        num_robots++;
164
        
165
        return id;
166
}
167

    
168
/**
169
 * Frees all resources associated with a robot, including
170
 * killing its process if necessary.
171
 *
172
 * @return zero on success, nonzero on failure
173
 **/
174
int robot_destroy(int id)
175
{
176
        Robot* r;
177

    
178
        if (id < 0 || id >= robots_size)
179
                return -1;
180
        r = &robots[id];
181
        if (r->id == 0)
182
                return -1;
183

    
184
    if (!shmdt(r->shared))
185
        {
186
                fprintf(stderr, "Failed to free shared memory.\n");
187
                return -1;
188
        }
189
        if (!shmctl(r->sharedMemID, IPC_RMID, NULL))
190
        {
191
                fprintf(stderr, "Failed to free shared memory.\n");
192
                return -1;
193
        }
194

    
195
        memset(r, 0, sizeof(Robot));
196
        r->id = -1;
197

    
198
        if (id < first_available_id)
199
                first_available_id = 0;
200
        
201
        return 0;
202
}
203

    
204
void robot_iterator_reset(void)
205
{
206
        iterator_pos = -1;
207
}
208

    
209
// note: addresses may change, replace with
210
// allocated memory
211
Robot* robot_iterator_next(void)
212
{
213
        if (iterator_pos >= robots_size)
214
                return NULL;
215
        do iterator_pos++;
216
        while (iterator_pos < robots_size && 
217
                        robots[iterator_pos].id == -1);
218
        
219
        if (iterator_pos >= robots_size)
220
                return NULL;
221
        
222
        return &(robots[iterator_pos]);
223
}
224

    
225
void sig_chld_handler(int sig)
226
{
227
  int ret,stat;
228

    
229
  pthread_mutex_lock(&all_finished_mutex);
230

    
231
  while((ret = waitpid(-1, &stat, WUNTRACED | WNOHANG)))
232
  {
233
    if(ret==-1)
234
      err(errno,"error waiting on robot");
235

    
236
    if(WIFSTOPPED(stat))
237
      finished++;
238
  }
239

    
240
  if (finished >= num_robots)
241
  {
242
    pthread_cond_signal(&all_finished_cond);
243
  }
244
  pthread_mutex_unlock(&all_finished_mutex);
245
}
246

    
247
void* robot_event_loop(void* arg)
248
{
249
        int i;
250
        int ret;
251

    
252
        //TODO: not exit if there is an error?
253

    
254
        while (1)
255
        {
256
                ret = pthread_mutex_lock(&all_finished_mutex);
257
                if(ret)
258
                  err(errno, "error locking mutex in even loop");
259
                // TODO: race condition for adding robots?
260
                if (finished < num_robots)
261
                {
262
                        ret = pthread_cond_wait(&all_finished_cond, &all_finished_mutex);
263
                        if(ret)
264
                          err(errno, "error waiting on condition variable");
265
                }
266
                finished = 0;
267

    
268
                ret = pthread_mutex_unlock(&all_finished_mutex);
269
                if(ret)
270
                  fprintf(stderr, "hmmm, error unlocking. errno: %d", errno);
271

    
272
                for (i = 0; i < robots_size; i++)
273
                        if (robots[i].id != -1)
274
                                robot_update(i);
275

    
276
                for (i = 0; i < robots_size; i++)
277
                {
278
                        if (robots[i].id == -1)
279
                                continue;
280
                        ret = kill(robots[i].pid, SIGCONT);
281
                        if(ret)
282
                          warn("error: could not kill resume robot proc.");
283
                }
284

    
285
                gui_refresh();
286
        }
287
}
288

    
289
void robot_update(int i)
290
{
291
        Robot* r = &(robots[i]);
292
        if (r->id == -1)
293
                return;
294
        move_robot(r);
295
        update_rangefinders(r);
296
}
297