Перейти к содержанию
    

Альтернативный вариант задания функции процесса

Э-э, мы, вроде, договорились, что если реализация не страдает, то принимаем. Т.ч. это можно не расширением, а основным вариантом делать. Клади в trunk, попробуем при случае.

Да я просто подумал, что незачем заставлять хорошего человека переступать через себя, если есть другой вариант, ничем не хуже. Расширение ничем не отличается в использовании, кроме необходимости добавления строчки #include "CustomProcess.h" в scmRTOS_extensions.h.

Думаю, что это не смертельно:)

В общем, подумай ещё немножко, а я тем временем допилю его (там ещё не охвачен вариант с двумя стеками, и ещё что-то по мелочи), и выложу куда скажешь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

то указатель был бы на функцию-член, а он совсем другой и зависящий от реализации.

Рассуждаю.

А если сделать дополнительную статическую функцию, скажем, start(), с параметром типа "тип процесса", в init_stack_frame() использовать ее вместо exec, в стековый фрейм на место регистра, в котором передается параметр, класть this, А функция уже будет делать param->exec(). Т.е. мы не вдаемся в дебри реализации указателя на функцию-член, этим занимается компилятор в start(), exec может быть нестатическим. Как-то так... Еще неплохо бы объявить exec как noreturn, чтобы компилятор догалася заменить вызов exec() на переход в нее. В принципе, такое изменение достойно релиза 4.1. И продумать совместимость с текущими исходниками.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Давайте я сюда добавлю ссылки на уже придуманные варианты. Вот вариант раз, вот вариант два. Я собственно их и хотел покрутить. Тем более, что с новым параметром шаблона это делать проще.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я изобрел ведосипед. "Говорят, у дураков мысли сходятся. Но у умных - ЧАЩЕ!"

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если сделать дополнительную статическую функцию, скажем, start(), с параметром типа "тип процесса", в init_stack_frame() использовать ее вместо exec, в стековый фрейм на место регистра, в котором передается параметр, класть this, А функция уже будет делать param->exec(). Т.е. мы не вдаемся в дебри реализации указателя на функцию-член, этим занимается компилятор в start(), exec может быть нестатическим. Как-то так... Еще неплохо бы объявить exec как noreturn, чтобы компилятор догалася заменить вызов exec() на переход в нее. В принципе, такое изменение достойно релиза 4.1. И продумать совместимость с текущими исходниками.

Нормальный ход. Вопрос остаётся с совместимостью. Как вариант - реализовать в расширениях, пользователь сам выбирает, что ему больше нравится. Я до сих пор не ощущаю необходимости объединять код реализации процесса с кодом прикладной программы, но если народ хочет (а его уже большинство по сравнению со мной), то возражать не могу.

 

P.S. Сам пока этим заниматься не могу, завален по уши текучкой, т.ч. инициативные товарищи - ваша инициатива - ваша реализация. :) Делайте расширение (думаю, сразу в trunk). Кстати, интересный вопрос, можно ли будет использовать гибридную схему - часть процессов по традиционному варианту, часть по новому? Навскидку вижу препятствие - разный способ вызова (напрямую и через указатель). Вот если б можно было совместить этих ужа с ежом, это было бы действительно клёво. Хотя бы тем, что совместимость точно никуда не денется.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кстати, интересный вопрос, можно ли будет использовать гибридную схему - часть процессов по традиционному варианту, часть по новому? Навскидку вижу препятствие - разный способ вызова (напрямую и через указатель). Вот если б можно было совместить этих ужа с ежом, это было бы действительно клёво. Хотя бы тем, что совместимость точно никуда не денется.
Когда уже всё в стековом кадре, то все равно должно быть. А вот для формирования...

Отдельно уже проверенные на совместимость process / custom_process, с применением process всё как раньше, но можно отнаследоваться от coustom_process вручную.

Отдельно какой-то process_object, который имеет свою статическую функцию и соответствующая функция для форимрования начального стекового кадра.

 

Хотя как раз для формирования кадра может быть одна функция, просто принимать два указателя -- на функцию и на аргумент для неё void* типа (или хорошо подумать какого -- у MSP430X ведь слово 16 бит а указатели могут быть длиннее?).

 

process / custom_process будут передвавть указатель на exec и 0

 

process_object будет передавать указатель на статическую функцию и this.

 

Переключателю задач и компании до лампочки, как оно было инициализировано.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всё-таки расставлю точки над i по поводу текущего варианта специализации функции процесса. На RSDN мне ответили, что реализация специализации функции шаблонного класса может быть сделана за пределами именованной области где был объявлен шаблон класса, но для этого надо обязательно надо сделать объявление этой специализации функции в той именованной области, где был объявлен шаблон класса.

Т.е. нельзя писать

typedef OS::process<OS::pr0, 200> TestProcess;

template<> void TestProcess::exec()
{
}

 

Правильно писать так:

typedef OS::process<OS::pr0, 200> TestProcess;

namespace OS
{
    template<> void TestProcess::exec(); // предварительно объявляем в void TestProcess::exec в namespace OS
}

// реализуем void TestProcess::exec в глобальной области видимости
template<> void TestProcess::exec()
{
}

 

В общем, как-то так

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В общем, задал вопрос на RSDN: http://www.rsdn.ru/forum/cpp/4963144.all. Там есть спецы, знающие стандарт наизусть :)

Ну да.

Только конкретно у gcc где-то нелады и вышло, что

namespace OS {
    template<> TProc1::exec();
}

template<> TProc1::exec()
{
    ...
}

он всё компилирует нормально, но выдаёт предупреждение redundant redeclaration и как предыдущее объявление тычет носом в OS_Kernel.h, в объявление неспециализированной функции в теле

        template<TPriority pr, size_t stack_size>
        class process : public TBaseProcess
        {
        public:
            INLINE_PROCESS_CTOR process();

            OS_PROCESS static void exec();  // <---- вот сюда

Но при этом просто

template<> TProc1::exec()
{
    ...
}

не собирает, тут ему уже того объявления недостаточно.

Вот и вышло, что минимальной кровью так, определение-объявление одним махом:

namespace OS {
    template<> TProc1::exec()
    {
        ...
    }
}

что тоже допускается.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну да.

Только конкретно у gcc где-то нелады и вышло, что

namespace OS {
    template<> TProc1::exec();
}

template<> TProc1::exec()
{
    ...
}

void потерялся. Поэтому и предупреждение вышло.

 

Тот пример, что я выкладывал сообщением выше компилируется без предупреждений.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

void потерялся. Поэтому и предупреждение вышло.

Ой, ну это я тут из головы забыл, в тексте void есть.

И без него совершенно другая ругань

namespace OS {
   template<> TProc1::exec(); // Строка 161
}

template<> TProc1::exec() // Строка 164
{
    DRIVER(PROC1,OUT);
    DRIVER(TIMER1_TO_PROC1,OUT);
    for(;;) {
        OFF(PROC1);
        Timer1_Ovf.wait();
        ON(PROC1);
        OFF(TIMER1_TO_PROC1);
    }
} // TProc1::exec()

==== Compiling ./src/main.cpp
./src/main.cpp:161:29: error: expected constructor, destructor, or type conversion before ‘;’ token
./src/main.cpp:164:25: error: ISO C++ forbids declaration of ‘exec’ with no type
./src/main.cpp:164:12: error: template-id ‘exec<>’ for ‘int OS::process<(OS::TPriority)0u, 100u>::exec()’ does not match any template declaration

Тот пример, что я выкладывал сообщением выше компилируется без предупреждений.
-Wredundant-decls есть?

С ним и с -Wredundant-decls

namespace OS {
   template<> void TProc1::exec(); // Строка 161
}

template<> void TProc1::exec()  // Строка 164
{
    DRIVER(PROC1,OUT);
    DRIVER(TIMER1_TO_PROC1,OUT);
    for(;;) {
        OFF(PROC1);
        Timer1_Ovf.wait();
        ON(PROC1);
        OFF(TIMER1_TO_PROC1);
    }
} // TProc1::exec()

==== Compiling ./src/main.cpp
./src/main.cpp:161:33: warning: redundant redeclaration of ‘static void OS::process<pr, stack_size>::exec() [with OS::TPriority pr = (OS::TPriority)0u, unsigned int stack_size = 100u]’ in same scope
../scmRTOS/Common/OS_Kernel.h:333:36: warning: previous declaration of ‘static void OS::process<pr, stack_size>::exec() [with OS::TPriority pr = (OS::TPriority)0u, unsigned int stack_size = 100u]’

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

-Wredundant-decls есть?

Да, с -Wredundant-decls такое-же предупреждение вылезло. Честно говоря даже не знаю что оно означает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я вот что подумал. В момент вызова TBaseProcess::init_stack_frame() у нас уже гарантированно имеется в нужных регистрах указатель на TBaseProcess. Таким образом, ничего формировать не надо, достаточно лишь честно сохранить контекст, подменив PC адресом начала функции-члена exec().

Для пробы можно сделать в конструкторе наследника, как-то так:

class BaseVirtualProcess : public TBaseProcess
{
public:
    INLINE_PROCESS_CTOR BaseVirtualProcess(stack_item_t * StackPoolEnd, TPriority pr)
        : TBaseProcess(StackPoolEnd, pr, 0 // - не нужен)
    {
        reinit_stack_frame();
    }
protected:
    OS_PROCESS virtual void exec() {}; // это наш виртуальный exec()
private:
    void reinit_stack_frame()
    {
        StackPointer += 16;                           // отменим деятельность TBaseProcess::init_stack_frame()
        *(--StackPointer)  = 0x01000000L;             // xPSR
        *(--StackPointer)  = reinterpret_cast<uint32_t>(&exec); // вот здесь адрес виртуального exec
        // и тут честно сохраняем остальные регистры, в том числе и self. (наверное будет ассемблерная процедура в порте)
    }
};

Правда reinterpret_cast здесь не проходит, надо какой-то ещё способ получить адрес exec().

 

---

Добавлю ссылочку про получение адреса функции-члена. На завтра:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не надо адрес функции-члена... Слова C++ extensions (а у кого-то может такого расширения не быть) и необходимость выключить предупреждение настораживают.

 

Лучше со статической функцией и this ей как аргумент. Прозрачнее.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

AHTOXA, Указатель на нестатическую функцию член класса в с++ - это не настоящий указатель. Его структура и размер зависят от компилятора. Поэтому чтобы узнать адрес ф-ции, надо выяснить где именно в структуре этого указателя "сидит" конкретно адрес для перехода.

А зачем вообще нужна нестатическая функция для процесса? Всё равно каждый процесс существует в единственном экземпляре.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

AHTOXA, Указатель на нестатическую функцию член класса в с++ - это не настоящий указатель. Его структура и размер зависят от компилятора. Поэтому чтобы узнать адрес ф-ции, надо выяснить где именно в структуре этого указателя "сидит" конкретно адрес для перехода.

Я понимаю это. Потому и говорил не об указателе на функцию-член, а об её адресе. Но вот нестандартность такого решения - это действительно плохо.

А зачем вообще нужна нестатическая функция для процесса? Всё равно каждый процесс существует в единственном экземпляре.

Чтобы обращаться к членам класса. Чтобы инициализировать их в конструкторе. Чтобы обращаться к унаследованным функциям класса, в конце концов. Короче, чтоб инкапсуляция:)

 

Не надо адрес функции-члена...

Ладно, ладно:)

Сделал вариант с виртуальным exec().

В процессе работы обратил внимание, что TKernelAgent::cur_proc() - private. Мне непонятно такое недоверие к потомкам TKernelAgent:)

Пришлось выкручиваться так:

TBaseProcess* base = const_cast<TBaseProcess*>(get_proc(cur_proc_priority()));

вместо тривиального

TBaseProcess* base = cur_proc();

 

Обратил внимание, что gcc довольно своеобразно понимает атрибут noreturn. Он перестаёт восстанавливать испорченные регистры, но всё равно сохраняет их! :)

За счёт этого, кстати, вариант с виртуальным exec не проигрывает по стеку варианту с вызовом Slon.exec() из SlonProc::exec().

Хотя нет, всё равно проигрывает. Там же вызов через виртуальный транк...

 

В общем, вот, смотрите/критикуйте:

#ifndef VIRTUALPROCESS_H_
#define VIRTUALPROCESS_H_

#include <scmRTOS.h>

namespace OS
{

class BaseVirtualProcess : public TBaseProcess, public TKernelAgent
{
public:
INLINE_PROCESS_CTOR BaseVirtualProcess(
		stack_item_t * StackPoolEnd
		, TPriority pr
	#if scmRTOS_DEBUG_ENABLE == 1
		, stack_item_t * aStackPool
	#endif
		) : TBaseProcess(
				StackPoolEnd
				, pr
				, launch_exec
			#if scmRTOS_DEBUG_ENABLE == 1
				, aStackPool
			#endif
			)
{
}
protected:
OS_PROCESS virtual void exec() { for(;;){} };
private:
OS_PROCESS static void launch_exec()
{
	for(;;) // eliminate compiler warning
	{
		TBaseProcess* base = const_cast<TBaseProcess*>(get_proc(cur_proc_priority()));
//			TBaseProcess* base = cur_proc();  // private!
		BaseVirtualProcess* proc = static_cast<BaseVirtualProcess*>(base);
		proc->exec();
	}
}
};


template<TPriority pr, size_t stack_size>
class VirtualProcess : public BaseVirtualProcess
{
public:
INLINE_PROCESS_CTOR VirtualProcess()
	: BaseVirtualProcess(&Stack[stack_size/sizeof(stack_item_t)]
	, pr
#if scmRTOS_DEBUG_ENABLE == 1
	, Stack
#endif
	)
{
}
private:
stack_item_t Stack[stack_size/sizeof(stack_item_t)];
};

} // namespace OS


#endif /* VIRTUALPROCESS_H_ */

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...