реклама на сайте
подробности

 
 
> Процесс, ограниченный по времени, помогите советом
_Pasha
сообщение May 24 2008, 05:17
Сообщение #1


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Доброго времени!
Требуется соорудить такую конструкцию:
предположим, у нас выполняется некий процесс. Считаем что-то, короче.
По наступлению прерывания от таймера необходимо из этого процесса выйти, да так, чтобы запомнить его состояние и впоследствии вернуться и продолжить его выполнение.
На ассемблере это делается элементарно.
Проблема в реализации этой конструкции на C - мешает нереентерабельность функций, огромные сохраняемые контексты.
Пока что представляю, как это сделать в рамках main() - с помощью setjump() и такой-то матери.smile.gif
Как это сделать в любой другой функции - как эти функции заточить по правильному - не имею понятия.
В идеале хочу выйти на что-то типа
Код
TIME_LIMITED_BLOCK(T_100us)
{/*code*/
}


взяв за основу for() как ATOMIC_BLOCK в WINAVR.

В общем,если есть какие-то советы, милости просим.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
_Pasha
сообщение Feb 14 2009, 13:06
Сообщение #2


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Опять приперло пересмотреть концепцию. Эх, ОС-пользователи, не близки вам страдания негритянского народа ! smile.gif
В общем, сделал красивше во сто раз, о чем и хвастаюсь:
Это препарированный timer.h
CODE

#ifndef TIMER_H_INCLUDED
#define TIMER_H_INCLUDED 1

typedef uint16_t timer_t;
//typedef uint32_t timer_t;

extern volatile timer_t ticks;
timer_t get_time(timer_t from);

#define ENABLE_LIFETIME_SW

#ifdef ENABLE_LIFETIME_SW
#include <setjmp.h>
typedef struct
{
timer_t time;
jmp_buf context;
} lifetime_t;

typedef void( * limited_proc_t)(void);
extern volatile lifetime_t *lifetime;
unsigned char time_limited(timer_t time, limited_proc_t process);

#endif

#endif // TIMER_H_INCLUDED


Это реализация time_limited

CODE


ISR(TIMER0_COMPA_vect)

{

ticks++;

#ifdef ENABLE_LIFETIME_SW
if((lifetime) && (lifetime->time >= ticks))
{
lifetime_t *tmp = lifetime;
lifetime = 0; // purge
longjmp(tmp->context,1);
}
#endif

}

/*...........*/

#ifdef ENABLE_LIFETIME_SW
unsigned char time_limited(timer_t time, limited_proc_t process)
{
lifetime_t list;
list.time = time + get_time(0);
if(setjmp(list.context)) return 1; // aborted
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) lifetime = &list;
process();
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) lifetime = 0;// UPD
return 0;
}
#endif


Тестовая программа
CODE


#include <avr/io.h>
#include "timer.h"
void MyProcess(void);
int main(void)
{
time_limited(100,MyProcess);
return 0;
}

void MyProcess(void)
{
volatile int a,b,c;
a = b + c;
return;
}


И попутно вопрос. Приятно удивила реентерабельность void MyProcess(void)
CODE
void MyProcess(void)
{
6c: df 93 push r29
6e: cf 93 push r28
70: 00 d0 rcall .+0 ; 0x72
72: 00 d0 rcall .+0 ; 0x74
74: 00 d0 rcall .+0 ; 0x76
76: cd b7 in r28, 0x3d ; 61
78: de b7 in r29, 0x3e ; 62
volatile int a,b,c;
a = b + c;
7a: 2b 81 ldd r18, Y+3 ; 0x03
7c: 3c 81 ldd r19, Y+4 ; 0x04
7e: 8d 81 ldd r24, Y+5 ; 0x05
80: 9e 81 ldd r25, Y+6 ; 0x06
82: 82 0f add r24, r18
84: 93 1f adc r25, r19
86: 9a 83 std Y+2, r25 ; 0x02
88: 89 83 std Y+1, r24 ; 0x01
return;
8a: 26 96 adiw r28, 0x06 ; 6
8c: 0f b6 in r0, 0x3f ; 63
8e: f8 94 cli
90: de bf out 0x3e, r29 ; 62
92: 0f be out 0x3f, r0 ; 63
94: cd bf out 0x3d, r28 ; 61
96: cf 91 pop r28
98: df 91 pop r29
9a: 08 95 ret


Это всегда так должно быть? Или этим можно управлять как-то ?
UPD исправлено - вставил пропущенную строчку.
Go to the top of the page
 
+Quote Post
defunct
сообщение Feb 15 2009, 00:19
Сообщение #3


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Я пользуюсь такой конецепцией.
Разбиваю все процессы на линейные быстро выполняющиеся блоки работающие со своими локальными структурами данных.
Например такой процесс:

Код
{
    TTHIS_PROCESS_CONTEXT context;

    for(;;)
    {
       wait_sema( DATA_READY );
       {
          for(i = 0; i < N; i++)
          {
               iteration( &context, i );
          }
          post_result( &cpntext);
       }
    }
}


Можно преврать в
Код
{
   static TTHIS_PROCESS_CONTEXT context;
   static i = 0;

   if (!DATA_READY)
       return;

   interation( &context, i );
   if (++i >= N)
   {
      post_result( &context );
      i = 0;
   }
}

Что это дает. Это дает возможность упростить планировщик до тупого поочередного вызыва функций всех процессов. Если процессу нужно подождать некоторое время, то достаточно его удалить из списка процессов на некоторое время. Такой подход позволяет наиболее эффективно использовать стек память - что для AVR весьма актуально. (Скажем имеется 1KB стека и 10 процессов. В классической ОС 1KB стека превратится в 100 байт стека для отдельно взятого процесса, а в описанном случае - каждый процесс получит в свое распоряжение этот 1KB).


Цитата
Решил пойти от обратного. Имеем априорно известное максимально допустимое время выполнения программы, выше которого все развалится. Поскольку ограничивать по времени надо процессы с наименьшим приоритетом, можно замерять и фиксировать максимальное время выполнения процесса, а затем перед следующим вызовом проверять, успеет оно поработать или нет. Если не успевает - то не вызывать. Количество не-вызовов тоже подсчитываем и, если их много, сбрасываем измеренное время выполнения в ноль. И на все 3-4 байт на задачу.

Вам хватит всего двух уровней приоритетов. Приоритет драйверов и приоритет пользовательских задач.
Планировщик можно построить как-то так:

Код
U32 local_time = 0;
U8 dispatch_cycle = 0;
volatile U8 timer_tick = 0;

Sys_Dispatch(void)
{
    Sys_Idle();

    if (!dispatch_cycle)
       return;

    dispatch_cycle = FALSE;

    for(int i = 0; i < NUM_USER_TASKS; i++)
        user_tasks[i]();
}


Sys_Idle(void)
{
    if (timer_tick)
    {
        local_time += 1;
        timer_tick = FALSE;
        dispatch_cycle = TRUE;
    }

    for(int i = 0; i < NUM_DRIVER_TASKS; i++)
        driver_tasks[ i ]();
}


U32 Sys_GetTime(void)
{
    return local_time;
}


Sys_Wait(U32 ticks)
{
    U32 time = Sys_GetTime();
    while(  Sys_GetTime() - time < ticks)
         Sys_Idle();
}


ISR(TICK_TIMER)
{
     timer_tick = TRUE;  
}


main()
{
     .... add user tasks to user task list
     .... add driver tasks to driver task list

     for(;;)
     {
         Sys_Dispatch();
     }
}


Внутри громоздких "user task" иногда вызывать Sys_Idle() или Sys_Wait() тем самым давая возможность отработать высокоприоритетным задачам.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Feb 15 2009, 12:14
Сообщение #4


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(defunct @ Feb 15 2009, 04:19) *
Внутри громоздких "user task" иногда вызывать Sys_Idle() или Sys_Wait() тем самым давая возможность отработать высокоприоритетным задачам.


Делал так тоже. То, что Вы говорите - тоже практически "классика жанра" кооперативной многозадачности. Добавлю свои 5 копеек:


Код
void Sys_Idle( char priority)

{
  switch(priority)
{
 case 0: do_statistic();
 case 1: do_screen();
 case 2: do_UART();
}
return;
}


Говоря по-русски, можно при вызове Sys_Idle() фильтровать вызываемые процессы по их приоритетам.
Go to the top of the page
 
+Quote Post
defunct
сообщение Feb 16 2009, 01:38
Сообщение #5


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(_Pasha @ Feb 15 2009, 14:14) *
Делал так тоже. То, что Вы говорите - тоже практически "классика жанра" кооперативной многозадачности.

Угу и никаких switch'ей как видите wink.gif
Для полного удобства работы можно еще добавить одноразовые колбеки с заданной задержкой запуска.
С их помощью управлять постановкой и снятием задачь из списка.

Цитата
Добавлю свои 5 копеек:

Ну понятно, что поле для улучшения есть.
Можно навводить event'ы, семафоры, временнЫе параметры (когда или через сколько кого запускать) и т.п.
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 24th July 2025 - 20:35
Рейтинг@Mail.ru


Страница сгенерированна за 0.01628 секунд с 7
ELECTRONIX ©2004-2016