ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Пятница
22 ноября
296673 Топик полностью
fk0, легенда (04.01.2012 22:36, просмотров: 144) ответил mazur на На примере таймерной службы. В прерывании таймера, настроенного, скажем на 1 мс, выставлялся флаг. Этот флаг можно было сбрасывать или в таймерной службе или в конце карусели.
#include <stddef.h>  #include <stdlib.h> #include <stdint.h> #define SIGNAL(name) signal_event(name, 1) typedef int8_t prio_t; #define PRIO_IDLE INT8_MAX typedef uint8_t sched_idx; typedef int_fast8_t (*event_func_t)(uintptr_t); typedef struct s_event_handler { struct s_event_handler *next; event_func_t func; uintptr_t arg; prio_t prio; #ifdef EVENT_CKSUM uint8_t cksum; #endif } event_handler_t; typedef struct s_event { event_handler_t *first, *current; sched_idx sq_idx; #ifdef EVENT_CKSUM uint8_t cksum; #endif uint8_t bcast; struct s_event *next; } event_t; #define BIND_EVENT(_event, _prio, _func, _arg) do { \ static event_handler_t _anon_event_handler = { \ .prio = (_prio), .func = (_func), .arg=(_arg) \ }; \ bind_event((_event), &_anon_event_handler); \ } while(0) #define EVENT_HANDLER(_func, _ename, _prio) \ static event_handler_t _ename = { \ .prio=(_prio), .func=(_func), .arg=(uintptr_t)&_ename \ } void signal_event(event_t *, uint_fast8_t bcast); void unbind_event(event_t *, event_handler_t *); void unbind_all(event_t *); void bind_event(event_t *, event_handler_t *); void eh_update(event_handler_t *, prio_t, event_func_t, uintptr_t); uint_fast8_t process_event(prio_t); void scheduler(void); static event_handler_t last_handler; static event_t last_pending; static event_t *pend_events = &last_pending; #define SCHED_INC_SIZE 32 static struct s_event **sched_queue=NULL; static sched_idx sched_len=0; static sched_idx sched_size=0; static sched_idx sched_maxlen=0; #if 1 void sched_debug(const char *s) { sched_idx n; const char *d=""; printf("%s", s); for (n=0; n<sched_len; n++) { assert(sched_queue[n]!=NULL); assert(sched_queue[n]->current!=NULL); printf("%s[%d] %8.8lx", d, sched_queue[n]->current->prio, (long)sched_queue[n]); d=", "; } puts(""); } #else #define sched_debug(s) #endif #ifdef EVENT_CKSUM static uint_fast8_t cksum(const void *data, size_t size) { const char *p=data; uint_fast8_t sum=0; while (size--) { sum+=*p, sum^=*p, p++; } return sum&0xFF; } #define EVENT_CHECK(e) \ assert(cksum((e), offsetof(event_t, cksum)==(e)->cksum) #define HANDLER_CHECK(h) \ assert(cksum((h), offsetof(event_handler_t, cksum)==(h)->cksum)) #define EVENT_CKSUM(e) do { \ (e)->cksum=cksum((e), offsetof(event_t, cksum)); \ } while(0) #define HANDLER_CKSUM(h) do { \ (h)->cksum=cksum((h), offsetof(event_handler_t, cksum)); \ } while(0) #else #define EVENT_CHECK(e) #define HANDLER_CHECK(h) #define EVENT_CKSUM(e) #define HANDLER_CKSUM(h) #endif static void sq_remove_first(void) { sched_idx n; assert(sched_len>0); if (--sched_len == 0) return; sched_queue[0]=sched_queue[sched_len]; n=0; while (1) { sched_idx l, r, m; l=2*n+1, r=2*n+2; m=n; #if 0 printf("n%u=%d (%8.8lx)", n, sched_queue[n]->prio, sched_queue[n]); if (l<sched_len) printf(", l%u=%d (%8.8lx)", l, sched_queue[l]->prio, sched_queue[l]); if (r<sched_len) printf(", r%u=%d (%8.8lx)\n", r, sched_queue[r]->prio, sched_queue[r]); #endif if (l<sched_len) { assert(sched_queue[l]!=NULL); assert(sched_queue[l]->current!=NULL && sched_queue[l]->current!=&last_handler); if (sched_queue[l]->current->prio < sched_queue[m]->current->prio) m=l; } if (r<sched_len) { assert(sched_queue[r]!=NULL); assert(sched_queue[r]->current!=NULL && sched_queue[r]->current!=&last_handler); if (sched_queue[r]->current->prio < sched_queue[m]->current->prio) m=r; } if (m!=n) { //puts(" -> swap"); event_t *t; t=sched_queue[m]; sched_queue[m]=sched_queue[n]; sched_queue[n]=t; sched_queue[m]->sq_idx=m+1; sched_queue[n]->sq_idx=n+1; n=m; continue; } break; } sched_debug("remove: "); } static sched_idx sq_inc_prio(sched_idx c) { sched_idx p; event_t *t; while (c>0) { p=(c-1)/2; assert(sched_queue[p]!=NULL); assert(sched_queue[c]!=NULL); assert(sched_queue[p]->current!=NULL && sched_queue[p]->current!=&last_handler); assert(sched_queue[c]->current!=NULL && sched_queue[c]->current!=&last_handler); if (sched_queue[p]->current->prio <= sched_queue[c]->current->prio) break; t=sched_queue[p]; sched_queue[p]=sched_queue[c]; sched_queue[c]=t; sched_queue[p]->sq_idx=p+1; sched_queue[c]->sq_idx=c+1; c=p; } return c; } static void sq_add(event_t *event) { sched_idx c; assert(event!=NULL); assert(event->current!=NULL && event->current!=&last_handler); c=sched_len, sched_len++; sched_queue[c]=event; event->sq_idx=sq_inc_prio(c)+1; } static void sq_remove_any(sched_idx c) { while (c > 0) { sched_idx p; event_t *t; p=(c-1)/2; assert(sched_queue[c]!=NULL); assert(sched_queue[p]!=NULL); t=sched_queue[p]; sched_queue[p]=sched_queue[c]; sched_queue[c]=t; sched_queue[c]->sq_idx=c+1; c=p; } sq_remove_first(); } void signal_event(event_t *evptr, uint_fast8_t bcast) { USE_CRITICAL; ASSERT(evptr != NULL); BEGIN_CRIT(); if (evptr->first!=NULL) { if (bcast) evptr->bcast=1; if (evptr->next==NULL) { evptr->next=pend_events; pend_events=evptr; } } END_CRIT(); } static void sched_event(event_t *evptr) { sched_idx c; assert(evptr!=NULL); EVENT_CHECK(evptr); if (evptr->first==NULL) return; assert(evptr->current!=NULL); if (evptr->current!=&last_handler) if (evptr->current->prio == evptr->first->prio) return; evptr->current=evptr->first; c=evptr->sq_idx-1; if ((int)c < 0) sq_add(evptr); else evptr->sq_idx=sq_inc_prio(c)+1; EVENT_CKSUM(evptr); } static void signal_pending(void) { USE_CRITICAL; event_t *e, *n; while (1) { BEGIN_CRIT(); e=pend_events; pend_events=&last_pending; END_CRIT(); if (e==&last_pending) break; do { assert(e!=NULL); sched_event(e); n=e->next; BEGIN_CRIT(); e->next=NULL; END_CRIT(); e=n; } while (e!=&last_pending); } sched_debug("signal: "); } void unbind_event(event_t *event, event_handler_t *handler) { event_handler_t *h, **nh; sched_idx c; uint_fast8_t is_planned=0; assert(handler != NULL && event != NULL); if (handler->next==NULL) return; if (event->first==NULL) return; nh=&event->first; h=*nh; while (h!=&last_handler && handler->prio >= h->prio) { assert(h->next!=NULL); if (h == event->current) is_planned=1; if (h == handler) { //BEGIN_CRIT(); *nh=h->next; //END_CRIT(); break; } nh=&h->next; h=h->next; } if (h!=handler) return; h->next=NULL; c=event->sq_idx-1; if ((int)c < 0) { assert(is_planned==0); return; } if (is_planned==0) return; assert(event->current!=&last_handler && event->current!=NULL); if (event->current->prio <= handler->prio) return; sq_remove_any(c); sq_add(event); } void unbind_all(event_t *event) { sched_idx c; event_handler_t *h, *n; assert(event != NULL); h=event->first; while (h!=&last_handler) { assert(h!=NULL); n=h->next; h->next=NULL; h=n; } event->first=event->current=NULL; c=event->sq_idx-1; if ((int)c >= 0) { sq_remove_any(c); } signal_pending(); } void bind_event(event_t *event, event_handler_t *handler) { event_handler_t *h, **nh; uint_fast8_t false_event=0; assert(event != NULL && handler != NULL); assert(handler->func != NULL); assert(handler->next == NULL); nh=&event->first; h=*nh; if (h==NULL) h=&last_handler; while (h!=&last_handler && handler->prio >= h->prio) { assert(h->next!=NULL); if (h == event->current) false_event=1; if (h == handler) return; nh=&h->next; h=h->next; } handler->next=h; //BEGIN_CRIT(); *nh=handler; //END_CRIT(); if (event->sq_idx==0) { sched_maxlen++; if (sched_maxlen > sched_size) { unsigned n; n=sched_size+SCHED_INC_SIZE; if (sizeof(sched_idx)==1) { if (n>=UINT8_MAX) n=UINT8_MAX-2; if (n <= sched_size) _Exit(EX_ASSERT); // TODO } sched_size=n; sched_queue=realloc(sched_queue, sched_size*sizeof(sched_queue[0])); if (sched_queue==NULL) _Exit(EX_NOMEM); } event->sq_idx=(sched_idx)-1; return; } if (event->sq_idx==(sched_idx)-1) return; } void eh_update(event_handler_t *h, prio_t prio, event_func_t func, uintptr_t arg) { h->prio=prio; h->func=func; h->arg=arg; } uint_fast8_t process_event(prio_t prio) { event_t *e; event_handler_t *h; int_fast8_t r; signal_pending(); if (sched_len==0) { return 0; } e=sched_queue[0]; assert(e->current!=NULL && e->current!=&last_handler); EVENT_CHECK(e); h=e->current; HANDLER_CHECK(h); if (h->prio > prio) { return 0; } assert(h->next!=NULL); HANDLER_CHECK(h->next); e->current=h->next; r=h->func(h->arg); if (e->bcast && r==0) { if (h->next!=&last_handler && h->prio >= h->next->prio) { EVENT_CKSUM(e); return 1; } } sq_remove_first(); e->sq_idx=(sched_idx)-1; if (e->current!=&last_handler) { if (e->bcast && r==0) sq_add(e); } else { e->bcast=0; } EVENT_CKSUM(e); return 1; } void scheduler(void) { while (sched_debug("run: "), process_event(PRIO_IDLE)); }
[ZX]