00001
00009
00010
00011
00012
00013
00014
00015 #include "fsm.h"
00016 #include <stdio.h>
00017
00018 const char *fsm_common_event_str(enum fsm_common_events ev)
00019 {
00020 #define E(name) case EV_##name: return "EV_" #name;
00021 switch (ev) {
00022 E(NOEVENT);
00023 E(INIT);
00024 E(EXIT);
00025 E(STATE_ENTERED);
00026 E(RETURN);
00027 E(TIMEOUT);
00028 E(TIMER);
00029 }
00030 #undef E
00031 return NULL;
00032 };
00033
00035 int fsm_nop_state(struct robo_fsm *fsm)
00036 {
00037 return RC_WAIT;
00038 }
00039
00040 static void gettimeofday_ts(struct timespec *ts)
00041 {
00042 struct timeval tv;
00043 gettimeofday(&tv, NULL);
00044
00045 ts->tv_sec = tv.tv_sec;
00046 ts->tv_nsec = tv.tv_usec * 1000;
00047 }
00048
00055 void __fsm_timespec_add_ms(struct timespec *ts, struct timespec *now, long ms)
00056 {
00057 struct timespec __now;
00058 if (!now) {
00059 gettimeofday_ts(&__now);
00060 now = &__now;
00061 }
00062 ts->tv_sec = now->tv_sec + ms/1000;
00063
00064 if ((now->tv_nsec+(ms%1000)*1000000)>1000000000L)
00065 ts->tv_sec++;
00066 ts->tv_nsec = (now->tv_nsec + (ms%1000)*1000000)%1000000000L;
00067 }
00068
00069 void __fsm_timespec_invalidate(struct timespec *ts)
00070 {
00071 ts->tv_sec = 0;
00072 ts->tv_nsec = 0;
00073 }
00074
00075 static inline int timespec_valid(struct timespec *ts)
00076 {
00077 return (ts->tv_sec != 0 || ts->tv_nsec != 0);
00078 }
00079
00080 static inline int timespec_cmp(struct timespec *ts1, struct timespec *ts2)
00081 {
00082 if (ts1->tv_sec < ts2->tv_sec)
00083 return -1;
00084 else if (ts1->tv_sec > ts2->tv_sec)
00085 return +1;
00086 else if (ts1->tv_nsec < ts2->tv_nsec)
00087 return -1;
00088 else if (ts1->tv_nsec > ts2->tv_nsec)
00089 return +1;
00090 else
00091 return 0;
00092 }
00093
00094 static fsm_event
00095 sem_wait_checked(struct robo_fsm *fsm)
00096 {
00097 int ret;
00098 fsm_event event;
00099 do {
00100 ret = sem_wait(&fsm->event_sent);
00101 if (ret != 0) {
00102 if (errno == EINTR)
00103 continue;
00104 perror("sem_wait");
00105 continue;
00106 }
00107 } while (0);
00108 event = fsm->sent_event;
00109 sem_post(&fsm->event_noticed);
00110 return event;
00111 }
00112
00113 static fsm_event
00114 sem_timedwait_checked(sem_t *sem, struct timespec *abs_timeout,
00115 struct robo_fsm *fsm, enum fsm_common_events timeout_event)
00116 {
00117 int ret;
00118 fsm_event event;
00119 do {
00120 ret = sem_timedwait(sem, abs_timeout);
00121 if (ret != 0) {
00122 switch (errno) {
00123 case ETIMEDOUT:
00124 fsm->now = *abs_timeout;
00125 __fsm_timespec_invalidate(abs_timeout);
00126 event = timeout_event;
00127 break;
00128 case EINTR:
00129 continue;
00130 default:
00131 gettimeofday_ts(&fsm->now);
00132 perror("sem_timedwait");
00133 fprintf(stderr, "TIMER ERROR %d timer=%ld+%.3f\n", ret, fsm->timer.tv_sec, (double)fsm->timer.tv_nsec/1000000000.0);
00134 fprintf(stderr, "TIMER ERROR %d now=%ld+%.3f\n\n\n", ret, fsm->now.tv_sec, (double)fsm->now.tv_nsec/1000000000.0);
00135 __fsm_timespec_invalidate(&fsm->timer);
00136 continue;
00137 }
00138 } else {
00139 gettimeofday_ts(&fsm->now);
00140 event = fsm->sent_event;
00141 sem_post(&fsm->event_noticed);
00142 }
00143 } while (0);
00144 return event;
00145 }
00146
00147 static inline fsm_event
00148 wait_for_event(struct robo_fsm *fsm)
00149 {
00150 fsm_event event;
00151 if (!(timespec_valid(&fsm->timeout) || timespec_valid(&fsm->timer))) {
00152
00153 event = sem_wait_checked(fsm);
00154 gettimeofday_ts(&fsm->now);
00155 } else {
00156
00157 if (timespec_valid(&fsm->timer) &&
00158 (!timespec_valid(&fsm->timeout) ||
00159 timespec_cmp(&fsm->timer, &fsm->timeout) <= 0)) {
00160
00161 event = sem_timedwait_checked(&fsm->event_sent, &fsm->timer, fsm, EV_TIMER);
00162 } else {
00163
00164 event = sem_timedwait_checked(&fsm->event_sent, &fsm->timeout, fsm, EV_TIMEOUT);
00165 }
00166 __fsm_timespec_invalidate(&fsm->timeout);
00167 }
00168 return event;
00169 }
00170
00171 static inline void
00172 handle_event(struct robo_fsm *fsm, fsm_event event)
00173 {
00174 int ret_code;
00175
00176 fsm->event = event;
00177
00178
00179 if (fsm->state)
00180 while ((ret_code = fsm->state(fsm)) != RC_WAIT);
00181 else
00182 fprintf(stderr, "FSM %s: fnc->act is NULL!!!\n", fsm->debug_name);
00183 fsm->event = EV_NOEVENT;
00184 }
00185
00189 static void *
00190 fsm_thread_routine(void *arg)
00191 {
00192 struct robo_fsm *fsm = (struct robo_fsm *)arg;
00193 fsm_event event = EV_NOEVENT;
00194
00195 while(event != EV_EXIT) {
00196 event = wait_for_event(fsm);
00197 handle_event(fsm, event);
00198 }
00199
00200 return NULL;
00201 }
00202
00212 void fsm_init(struct robo_fsm *fsm, char *debug_name)
00213 {
00214
00215
00216 fsm->sent_event = EV_INIT;
00217 sem_init(&fsm->event_sent, 0, 1);
00218
00219
00220 sem_init(&fsm->event_noticed, 0, 0);
00221
00222 __fsm_timespec_invalidate(&fsm->timeout);
00223 __fsm_timespec_invalidate(&fsm->timer);
00224
00225
00226 fsm->fnc_sp = &fsm->fnc_stack[0];
00227
00228
00229 fsm->state = &fsm_nop_state;
00230
00231
00232 fsm->debug_name = debug_name;
00233 }
00234
00245 int fsm_start(struct robo_fsm *fsm, pthread_attr_t *attr)
00246 {
00247 int ret;
00248 ret = pthread_create(&fsm->threadid, attr,
00249 fsm_thread_routine,
00250 (void *)fsm);
00251 return ret;
00252 }
00253
00262 int fsm_destroy(struct robo_fsm *fsm)
00263 {
00264 sem_destroy(&fsm->event_sent);
00265 sem_destroy(&fsm->event_noticed);
00266 return 0;
00267 }
00268