Как правильно вызывать hal_exit()?

Обсуждение установки, настройки и использования LinuxCNC. Вопросы по Gкоду.
perelep
Новичок
Сообщения: 39
Зарегистрирован: 29 янв 2022, 10:49
Репутация: 0
Контактная информация:

Как правильно вызывать hal_exit()?

Сообщение perelep »

Приветствую!

Не могу разобраться как, и где правильно вызывать hal_exit(). Если происходит завершение без вызова hal_exit(), например при Ctrl-Z, Ctrl-C и тд, то при следующем запуске получаю ошибку:
HAL: ERROR: duplicate component name '<имя компонента>'
HAL: ERROR: component -22 not found
Через signal Handler сделать не получается, потому как метод signalHandler - static. Мне из него не добраться до id компонента.
Деструктор, когда ловится signal тоже не запускается.
Видел тут примеры с безусловным переходом, но это совсем табуретка. На первом курсе вроде бы как объясняют, что использование goto совсем неприличный стиль программирования.

На всякий случай напишу зачем мне это надо все. Решил под себя написать компонент для управления частотником по modbus и оформить все это дело по-человечески, в виде класса и тд. Да и на будущее, мало ли какой компонент написать захочется...
Последний раз редактировалось perelep 03 авг 2022, 00:13, всего редактировалось 2 раза.
alex_sar
Мастер
Сообщения: 1672
Зарегистрирован: 28 авг 2018, 17:13
Репутация: 278
Настоящее имя: Алексей
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение alex_sar »

perelep писал(а): Видел тут примеры с безусловным переходом, но это совсем табуретка. На первом курсе вроде бы как объясняют, что использование goto совсем неприличный стиль программирования.
А на третьем объясняют что если надо, то можно.
perelep
Новичок
Сообщения: 39
Зарегистрирован: 29 янв 2022, 10:49
Репутация: 0
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение perelep »

И еще объясняют, что нет ситуаций, когда это необходимо :) И что используют goto тогда, когда не умеют правильно.
alex_sar
Мастер
Сообщения: 1672
Зарегистрирован: 28 авг 2018, 17:13
Репутация: 278
Настоящее имя: Алексей
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение alex_sar »

goto нельзя использовать потому что это потенциально опасно с точки зрения внесения багов.

если у вас код вмещается на пару-тройку страниц, как в любом нормальном hal компоненте, ничего особо страшного в goto нет.
perelep
Новичок
Сообщения: 39
Зарегистрирован: 29 янв 2022, 10:49
Репутация: 0
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение perelep »

Я понимаю что можно. Но про то и вопрос был, как избежать этого.
perelep
Новичок
Сообщения: 39
Зарегистрирован: 29 янв 2022, 10:49
Репутация: 0
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение perelep »

Goto рядом со всякими private, try, catch, изоляцией данных и тд совсем не смотрится. Это прям совсем не в духе С++.
alex_sar
Мастер
Сообщения: 1672
Зарегистрирован: 28 авг 2018, 17:13
Репутация: 278
Настоящее имя: Алексей
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение alex_sar »

А где увидели goto то?
https://github.com/LinuxCNC/linuxcnc/bl ... _generic.c

Код: Выделить всё

void rtapi_app_exit(void){
  //everything is hal_malloc-ed which saves a lot of cleanup here
   hal_exit(comp_id);
} 
perelep
Новичок
Сообщения: 39
Зарегистрирован: 29 янв 2022, 10:49
Репутация: 0
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение perelep »

Ну, в том же vfdmod, который взял за основу.
perelep
Новичок
Сообщения: 39
Зарегистрирован: 29 янв 2022, 10:49
Репутация: 0
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение perelep »

Там то что мне нужно, решено с помощью

Код: Выделить всё

goto fail;
И

Код: Выделить всё

fail:
    hal_exit(hal_comp_id);
    delete [] hal_udata;
    fprintf(stderr, "%s: fatal error.\n", qPrintable(exeName));
    return -1;
И в вашем примере тоже такая же история (строка 275):

Код: Выделить всё

fail0:
    hal_exit(comp_id);
    return -1;
alex_sar
Мастер
Сообщения: 1672
Зарегистрирован: 28 авг 2018, 17:13
Репутация: 278
Настоящее имя: Алексей
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение alex_sar »

так этож чтоб код не дублировать.
возьмите да накопипастьте вместо goto : { hal_exit(comp_id); return -1; }
perelep
Новичок
Сообщения: 39
Зарегистрирован: 29 янв 2022, 10:49
Репутация: 0
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение perelep »

Вот кусок кода. Точнее, это уже псевдокод, удалено все лишнее:

Код: Выделить всё

class altivar320{

	private:
		modbus_t *ctx;
		int hal_comp_id;
		static void signalHandler(int signum);
		
	public: 
		altivar320(){
			ctx = modbus_new_rtu(<какие-то значения для инициализации>);
			modbus_set_slave(ctx, 1);
			
		    hal_ready(hal_comp_id);
		}

		~altivar320(){
			try{
				hal_exit(this->hal_comp_id);
				modbus_free(this->ctx);
				printf("%s\n", "Destructor");
			}
			catch(const std::exception& e){
				printf("%s\n", "catch, destructor");
			}
		}

		int main_loop();

};

void altivar320::signalHandler(int signum){
	printf("Caught signal %d\n",signum);
	//Здесь я не могу вызвать hal_exit(this->hal_comp_id); Потому как нельзя использовать this из-за static
	//До деструктора дело тоже не доходит
}

int altivar320::main_loop(){
	signal(SIGINT, this->signalHandler);
    signal(SIGKILL, this->signalHandler);
    signal(SIGTERM, this->signalHandler);
    signal(SIGTSTP, this->signalHandler);
	try{
		while (1){
      		printf("%s\n", "while");
      		throw 1;
		}
	}
	catch(int){
        printf("%s\n", "сatch, main loop");
	}
	return 1;
}

int main(){
	altivar320 alt320;
	alt320.main_loop();
	return 1;
}
Если так сделать (или еще как угодно, лишь бы не через signal), то тут же выходим их цикла, запускается деструктор, вызывается hal_exit(), нет ни каких ошибок при последующем запуске.
Но если создается ситуация, когда доходит дело до signalHandler (завершение по Ctrl-Z, например), то hal_exit() мне уже не вызвать. И больше мне этот код не запустить, получаю ошибку:

Код: Выделить всё

HAL: ERROR: duplicate component name '<имя компонента>'
HAL: ERROR: component -22 not found
alex_sar
Мастер
Сообщения: 1672
Зарегистрирован: 28 авг 2018, 17:13
Репутация: 278
Настоящее имя: Алексей
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение alex_sar »

если прям хочется сделать красиво, в signal надо передавать указатель на метод конкретного объекта. сделать это точно можно.

однако вся эта ООП красота тут ни к чему, ибо signal заменяет предыдущий обработчик, а не добавляет новый.
поэтому пишите comp_id в глобальную переменную, как все и делают.
Аватара пользователя
MX_Master
Мастер
Сообщения: 7465
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3088
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение MX_Master »

Пример из моего драйвера - https://github.com/allwincnc/linuxcnc/b ... isc.c#L992
perelep
Новичок
Сообщения: 39
Зарегистрирован: 29 янв 2022, 10:49
Репутация: 0
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение perelep »

Спасибо! По делу мне ответить пока нечего, нужно время разобраться.
rtapi_app, это точно мой случай? Это ж realtime hal component? У меня по идее user space HAL component... Тот же vfdmod он user space
alex_sar
Мастер
Сообщения: 1672
Зарегистрирован: 28 авг 2018, 17:13
Репутация: 278
Настоящее имя: Алексей
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение alex_sar »

perelep писал(а): 03 авг 2022, 21:47 Спасибо! По делу мне ответить пока нечего, нужно время разобраться.
rtapi_app, это точно мой случай? Это ж realtime hal component? У меня по идее user space HAL component... Тот же vfdmod он user space
вообще нет, гоню. по красоте вот как надо.

хранить список созданных объектов
а по сигналу из статического обработчика делать delete каждому по списку.
вот так будет по феншую
perelep
Новичок
Сообщения: 39
Зарегистрирован: 29 янв 2022, 10:49
Репутация: 0
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение perelep »

Проще уж тогда вот так сделать:

Код: Выделить всё

static volatile sig_atomic_t sig_caugh=1;

class altivar320{

	private:
		modbus_t *ctx;
		int hal_comp_id;
		static void signalHandler(int signum);
		
	public: 
		altivar320(){
			ctx = modbus_new_rtu(<какие-то значения для инициализации>);
			modbus_set_slave(ctx, 1);
			
		    hal_ready(hal_comp_id);
		}

		~altivar320(){
			try{
				hal_exit(this->hal_comp_id);
				modbus_free(this->ctx);
				printf("%s\n", "destructor");
			}
			catch(const std::exception& e){
				printf("%s\n", "catch, destructor");
			}
		}

		int main_loop();

};

void altivar320::signalHandler(int signum){
	printf("Caught signal %d\n",signum);
	sig_caugh=0;
}

int altivar320::main_loop(){
	signal(SIGINT, this->signalHandler);
	signal(SIGKILL, this->signalHandler);
	signal(SIGTERM, this->signalHandler);
	signal(SIGTSTP, this->signalHandler);
	while (sig_caugh){
		printf("%s\n", "while");
	}
	return 1;
}

int main(){
	altivar320 alt320;
	alt320.main_loop();
	return 1;
}
Только это выглядит не шибко хорошо.
Аватара пользователя
MX_Master
Мастер
Сообщения: 7465
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3088
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение MX_Master »

Проще С++ не расчехлять :)
perelep
Новичок
Сообщения: 39
Зарегистрирован: 29 янв 2022, 10:49
Репутация: 0
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение perelep »

Еще вот такой вариант придумался

Код: Выделить всё

class altivar320{

	private:
		modbus_t *ctx;
		int hal_comp_id;
		static void signalHandler(int signum);
		
	public: 
		altivar320(){
			ctx = modbus_new_rtu(<какие-то значения для инициализации>);
			modbus_set_slave(ctx, 1);
			
		    hal_ready(hal_comp_id);
		}

		~altivar320(){
			try{
				hal_exit(this->hal_comp_id);
				modbus_free(this->ctx);
				printf("%s\n", "destructor");
			}
			catch(const std::exception& e){
				printf("%s\n", "catch/destructor");
			}
		}

		int main_loop();

};

void altivar320::signalHandler(int signum){
	throw signum;
}

int altivar320::main_loop(){
	signal(SIGINT, this->signalHandler);
	signal(SIGKILL, this->signalHandler);
	signal(SIGTERM, this->signalHandler);
	signal(SIGTSTP, this->signalHandler);
	try{
		while (1){
			printf("%s\n", "while");
		}
	}
	catch(int x){
		printf("%s\n", "catch/while");
		printf("Caught signal %d\n",x);
	}
	return 1;
}

int main(){
	altivar320 alt320;
	alt320.main_loop();
	return 1;
}
alex_sar
Мастер
Сообщения: 1672
Зарегистрирован: 28 авг 2018, 17:13
Репутация: 278
Настоящее имя: Алексей
Контактная информация:

Re: Как правильно вызывать hal_exit()?

Сообщение alex_sar »

одно могу сказать.
если на такую чушь тратить несколько дней, результат вряд ли будет.
Ответить

Вернуться в «LinuxCNC»