Перезагрузка linux от другого

Содержание
  1. Выключение и перезагрузка Linux. Shutdown и Reboot
  2. Команда shutdown
  3. Синтаксис команды shutdown
  4. Перезагрузить систему
  5. Выключить компьютер
  6. Перезагрузка или выключение Linux по времени
  7. Отправка сообщения перед перезагрузкой или выключением
  8. Отмена запланированной перезагрузки или выключения
  9. linux-notes.org
  10. Перезагрузка/выключение компьютера из командной строки
  11. Перезагрузка компьютера из командной строки
  12. Выключение компьютера из командной строки
  13. Добавить комментарий Отменить ответ
  14. unixforum.org
  15. Периодическая перезагрузка Linux при стабильной работе Windows
  16. Периодическая перезагрузка Linux при стабильной работе Windows
  17. Re: Периодическая перезагрузка Linux при стабильной работе Windows
  18. Re: Периодическая перезагрузка Linux при стабильной работе Windows
  19. Re: Периодическая перезагрузка Linux при стабильной работе Windows
  20. Re: Периодическая перезагрузка Linux при стабильной работе Windows
  21. Re: Периодическая перезагрузка Linux при стабильной работе Windows
  22. Re: Периодическая перезагрузка Linux при стабильной работе Windows
  23. Re: Периодическая перезагрузка Linux при стабильной работе Windows
  24. 5 способов выключить компьютер с Linux через терминал
  25. 1. Отключение
  26. Перезапустить с -r
  27. 2. Перезагрузка
  28. 3. Остановить
  29. 4. Poweroff
  30. 5. Аварийный вариант: REISUB
  31. Помогите, я случайно выключил свой Linux компьютер или сервер!
  32. Реализация горячей перезагрузки С++ кода в Linux
  33. Зачем?
  34. Требования и постановка задачи
  35. Реализация
  36. Перезагрузка функций
  37. Поиск функций в скопмилированной программе
  38. Единицы трансляции
  39. Обработка зависимостей
  40. Перенос статических переменных
  41. Собираем все вместе

Выключение и перезагрузка Linux. Shutdown и Reboot

Команда shutdown

Команда shutdown предназначена для выключения и перезагрузки компьютера, используя командую строку Linux. shutdown также позволяет перезагрузить или выключить компьютер в заданное время или через заданный интервал времени.

Синтаксис команды shutdown

[опции] — указывает действие, которое необходимо выполнить.
[время] — время или интервал для выполнения действия.
[сообщение] — сообщение, рассылаемое залогиненным пользователям.

Перезагрузить систему

Для перезагрузки системы используется ключ -r . Чтобы немедленно запустить перезапуск системы используется команда:

Для перезагрузки Linux также можно использовать команду reboot. Она является аналогом команды shutdown -r . Для перезагрузки Linux из командной строки, с использованием команды reboot, необходимо выполнить:

Выключить компьютер

Чтобы корректно завершить систему и выключить компьютер используется команда:

Также можно использовать команду reboot с ключом -p :

Перезагрузка или выключение Linux по времени

Для команды shutdown можно указать точное время или интервал времени, через который необходимо перезагрузить или выключить систему. Рассмотрим примеры.

Выключить систему через 15 минут:

Выключить систему в 13 часов 10 минут:

Перезагрузить систему через 10 минут:

Отправка сообщения перед перезагрузкой или выключением

Если система используется несколькими пользователями, то бывает полезно предупредить их перед выполнением перезагрузки или выключением системы. Для этого в конце команды shutdown пишется соответствующее сообщение:

Отмена запланированной перезагрузки или выключения

Если вы выполнили команду shutdown и установили соответствующее время для ее выполнения, то чтобы отменить данное действие используется ключ -c :

Дополнительную информацию по командам shutdown и reboot можно получить, выполнив

К перезагрузке или выключению компьютера из командной сроки Linux иногда прибегают, когда «система» или какой-нибудь процесс или группа процессов серьезно повисла. Смотрите также как завершать процессы, используя команду kill.

Источник

linux-notes.org

Перезагрузка/выключение компьютера из командной строки

Хотелось бы рассказать как правильно выключать/перезапускать компьютер или сервер с командной строки. Некоторые могут сказать что есть всего пару команд которые позволяют это сделать, но я постараюсь привести как можно больше готовых примеров. Некоторые, знают не все возможности Unix/Linux. В этой статье «Перезагрузка/выключение компьютера из командной строки» я приведу готовые примеры по выключению и перезагрузки серверов под управлением ОС Unix и Linux.

Для начала, нужно открыть консоль (терминал). После чего, выполнить одну из команд что ниже.

Перезагрузка компьютера из командной строки

Самый простой способ перезапустить сервер, использовать следующую команду:

Вас попросят ввести пароль от пользователя с правами «суперпользователя» или «root» и после чего сервер перезапустится.

Существует утилита под названием shutdown, которую тоже можно использовать для перезапуска:

Запланировать выключение системы на 09 часа 09 минут:

Для отмены запланированного выключения служит команда:

Так же, можно перезапустить ПК еще одной командой:

Выключение компьютера из командной строки

Самый простой способ выключить ПК или сервер с командной строки — это использовать утилиту shutdown:

Можно указать время через которое он выключиться сам ( минуты), я укажу 120 мин (2ч) в качестве примера:

Есть и другой способ выключить сервер, для этого служит еще одна команда:

Вот еще один вариант выключить свой сервер/ПК:

Если нужно выключить вашу ОС, можно использовать:

Запланируем выключение сервера или своего ПК на нормальное (корректное) выключение, скажем, на 23:59 и отправим задание в фоновый режим:

Тоже способ выключения системы:

Тема «Перезагрузка/выключение компьютера из командной строки» завершена. Надеюсь было познавательно.

Добавить комментарий Отменить ответ

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Источник

unixforum.org

Форум для пользователей UNIX-подобных систем

  • Темы без ответов
  • Активные темы
  • Поиск
  • Статус форума

Периодическая перезагрузка Linux при стабильной работе Windows

Периодическая перезагрузка Linux при стабильной работе Windows

Сообщение aes78 » 17.10.2019 16:46

Re: Периодическая перезагрузка Linux при стабильной работе Windows

Сообщение GalakhovR » 17.10.2019 17:16

Re: Периодическая перезагрузка Linux при стабильной работе Windows

Сообщение Hephaestus » 17.10.2019 17:17

Я правильно понял, что спонтанные перезагрузки происходят во время установки Linux,
и ни одна попытка установки не дошла до конца?

Проверяйте питание вообще и питание винчестера в частности.
Проверяйте кабели Sata.
Проверяйте память.
Любой из этих факторов вполне может повлиять на успешное завершение установки.

Windows 7 работает стабильно, но:
во-первых, она уже установлена,
во-вторых, проблемы с питанием, памятью и пр. могут быть менее заметны под Win (до поры, до времени),
но это не значит, что их нет.

Re: Периодическая перезагрузка Linux при стабильной работе Windows

Сообщение s.xbatob » 17.10.2019 17:20

Re: Периодическая перезагрузка Linux при стабильной работе Windows

Сообщение algri14 » 18.10.2019 00:06

Re: Периодическая перезагрузка Linux при стабильной работе Windows

Сообщение Hephaestus » 18.10.2019 07:13

Re: Периодическая перезагрузка Linux при стабильной работе Windows

Сообщение aes78 » 18.10.2019 15:01

Я правильно понял, что спонтанные перезагрузки происходят во время установки Linux,
и ни одна попытка установки не дошла до конца?

Проверяйте питание вообще и питание винчестера в частности.
Проверяйте кабели Sata.
Проверяйте память.
Любой из этих факторов вполне может повлиять на успешное завершение установки.

Windows 7 работает стабильно, но:
во-первых, она уже установлена,
во-вторых, проблемы с питанием, памятью и пр. могут быть менее заметны под Win (до поры, до времени),
но это не значит, что их нет.

Re: Периодическая перезагрузка Linux при стабильной работе Windows

Сообщение Bizdelnick » 18.10.2019 15:21

Источник

5 способов выключить компьютер с Linux через терминал

Ни одна операционная система не идеальна. Даже если это так, могут быть проблемы с драйверами и приложениями. Linux не является исключением. Несмотря на то, что он более стабилен, чем Windows, вероятно, придет время, когда вам нужно перезагрузить компьютер с Linux.

Читайте также:  Что такое windows script host не удается найти файл сценария

Но как ты мог это сделать? Доступны несколько команд для выключения или перезагрузки компьютера Linux через терминал.

Давайте посмотрим на них по очереди и рассмотрим, как и когда следует использовать эти команды.

1. Отключение

Если вы закончили работу с Linux, решение просто отключить его, для это можно использовать синтаксис команды:

shutdown [option] [time] [message]

Например, чтобы немедленно выключить компьютер, вы должны использовать:

Где -h означает остановку, а now – сейчас, что означает, инструкция должна быть выполнена немедленно. Различные задержки могут быть использованы. Например, вместо этого вы можете использовать +5, что скажет компьютеру выполнить процедуру выключения через пять минут.

Если вы хотите использовать message (сообщение), оно будет мигать всем зарегистрированным пользователям:

shutdown -h +5 «Сервер выключается, сохраните свою работу и выйдите из системы.»

Помните, что вы можете найти полный список переключателей для этих команд, введя:

Перезапустить с -r

Альтернативный вариант – использовать команду -r для перезагрузки компьютера. Она используется вместо -h, поэтому, для перезагрузки компьютера или сервера вы можете использовать:

shutdown -r +5 «Сервер перезагружается через пять минут, сохраните свою работу и выйдите из системы.»

Любое запланированное отключение или перезапуск можно отменить, введя команду -c:

2. Перезагрузка

Поскольку команда shutdown имеет опцию перезапуска, неудивительно, что команда reboot имеет опцию shutdown.

Стандартная команда перезагрузки:

Это предложит вашему компьютеру выключиться и снова включиться. Однако, если вы хотите выключить устройство, то ключ -p будет работать:

Другой вариант – принудительная перезагрузка. Это может быть полезно, если приложение или служба зависли и вам нужно быстро перезагрузиться:

Эта команда принудительно перезагрузит ваш Linux ПК.

3. Остановить

Мы уже видели переключатель -h выше, но остановка может использоваться как команда сама по себе. Это приведет к немедленному отключению компьютера с помощью простого четырехбуквенного слова:

Переключатель -f также можно использовать с остановкой, но результаты противоречивы, и может привести к проблемам стабильности системы.

4. Poweroff

Вы можете предпочесть терминологию команды poweroff. Это делает то же самое, что и halt, за исключением того, что ввод текста занимает в два раза больше времени.

Однако, кроме использования -f для принудительного отключения питания, вы также можете использовать ключ -w для регистрации вызова перезагрузки системы в /var/log/wtmp. Это потенциально полезный инструмент отладки, как -verbose, который может помочь с проблемами при завершении работы.

5. Аварийный вариант: REISUB

Все вышеперечисленные команды можно использовать в ситуациях, когда система работает без проблем. Но что делать, если компьютер или сервер зависает и не может быть перезагружен приемлемым способом?

Ответ тогда – комбинация клавиатуры. Если вы переключились с Windows, вы, вероятно, знаете, что Ctrl + Alt + Del отображает меню с выключением в качестве опции. Если удерживать дольше, машина выключится автоматически. В то же время на Mac вы просто должны удерживать кнопку питания (опция, которая также работает на оборудовании Windows).

В Linux комбинация клавиш для перезагрузки Alt + Print Screen + B. Однако, если это не работает или существует более сложная проблема, вы можете изменить комбинацию, используя до шести клавиш.

Это известно как REISUB, из-за следующей вынужденной аббревиатуры:

  • unRaw – возвращает управление клавиатурой обратно с сервера X-дисплея.
  • tErminate – посылает сигнал завершения SIGTERM всем процессам для корректного завершения.
  • kIll – как и выше, но сигнал SIGKILL, который вызывает немедленное завершение процессов.
  • Sync – сбрасывает данные на диск.
  • Unmount – перемонтирует все файловые системы в состояние только для чтения.
  • reBoot – что и следовало ожидать.

Чтобы это сработало, вы должны удерживать Alt + Print Screen, а затем, поочерёдно нажимать клавиши: R E I S U B, в этом же порядке. Задержка между каждым нажатием должна составлять 1-2 секунды. Это необходимо для того, чтобы дать немного времени на выполнение всех вышеперечисленных процессов. Обратите внимание, что этот метод обычно не работает на компьютерах с архитектурой ARM.

Помогите, я случайно выключил свой Linux компьютер или сервер!

Мы видели, как отменить команду выключения или перезапуска. Однако бывают ситуации, что вы запускаете команду выключения, когда выполняется жизненно важный процесс, особенно на удаленном сервере. Обойти это можно, установив molly-guard, который может отменить отключение, проверив определенные параметры.

Например, есть скрипт, который проверяет наличие сессий SSH. Если вы отправите команду перезагрузки, остановки или выключения molly-guard потребует имя хоста, который вы собираетесь закрыть.

Для этого установите molly-guard в терминал:

sudo apt-get install molly-guard

Поскольку molly-guard работает в фоновом режиме, он обнаружит такую ​​команду, как poweroff, и сообщит, что был обнаружен сеанс SSH. Затем вы можете ввести имя хоста сервера для подтверждения выключения или нажать Ctrl + C для отмены. Полезно!

Эти пять способов выключения компьютера Linux из командной строки особенно полезны, поскольку их можно использовать на самом компьютере или через удаленный SSH. Поскольку эти команды очень лаконичны, они пригодны для быстрого использования – что может привести к случайной перезагрузке время от времени! К счастью, утилиты molly-guard достаточно, чтобы этого избежать.

Чтобы узнать больше о командах Linux, ознакомьтесь с нашей справочной таблицей.

Источник

Реализация горячей перезагрузки С++ кода в Linux

* Ссылка на библиотеку в конце статьи. В самой статье изложены механизмы, реализованные в библиотеке, со средней детализацией. Реализация для macOS еще не закончена, но она мало чем отличается от реализации для Linux. Здесь в основном рассматривается реализация для Linux.

Гуляя по гитхабу одним субботним днем, я наткнулся на библиотеку, реализующую обновление c++ кода налету для windows. Сам я слез с windows несколько лет назад, ни капли не пожалел, и сейчас все программирование происходит либо на Linux (дома), либо на macOS (на работе). Немного погуглив, я обнаружил, что подход из библиотеки выше достаточно популярен, и msvc использует ту же технику для функции «Edit and continue» в Visual Studio. Проблема лишь в том, что я не нашел ни одной реализации под не-windows (плохо искал?). На вопрос автору библиотеки выше, будет ли он делать порт под другие платформы, ответ был отрицательный.

Сразу скажу, что меня интересовал только вариант, в котором не пришлось бы менять существующий код проекта (как, например, в случае с RCCPP или cr, где весь потенциально перезагружаемый код должен быть в отдельной динамически загружаемой библиотеке).

«Как так?» — подумал я, и принялся раскуривать фимиам.

Зачем?

Я в основном занимаюсь геймдевом. Большую часть моего рабочего времени я трачу на написание игровой логики и верстку всякого визуального. Кроме этого я использую imgui для вспомогательных утилит. Мой цикл работы с кодом, как вы, наверное, догадались, это Write -> Compile -> Run -> Repeat. Происходит все довольно быстро (инкрементальная сборка, всякие ccache и т.п.). Проблема тут в том, что этот цикл приходится повторять достаточно часто. Например, пишу я новую игровую механику, пусть это будет «Прыжок», годный, управляемый Прыжок:

Читайте также:  How to find and delete the oldest file linux bash

1. Написал черновую реализацию на основе импульса, собрал, запустил. Увидел, что случайно прикладываю импульс каждый кадр, а не один раз.

2. Пофиксил, собрал, запустил, теперь нормально. Но надо бы абсолютное значение импульса побольше взять.

3. Пофиксил, собрал, запустил, работает. Но как-то ощущается не так. Надо попробовать на основе силы сделать.

4. Написал черновую реализацию на основе силы, собрал, запустил, работает. Надо бы только мгновенную скорость в момент прыжка менять.
.

10. Пофиксил, собрал, запустил, работает. Но все еще не то. Наверное нужно попробовать реализацию на основе изменения gravityScale .
.

20. Отлично, выглядит супер! Теперь выносим все параметры в редактор для геймдиза, тестируем и заливаем.
.

30. Прыжок готов.

И на каждой итерации нужно собрать код и в запустившемся приложении добраться до места, где я могу попрыгать. На это обычно уходит не меньше 10 секунд. А если я могу попрыгать только на открытой местности, до которой еще надо добраться? А если мне нужно уметь запрыгивать на блоки высотой N единиц? Тут мне уже нужно собрать тестовую сцену, которую тоже надо отладить, и на которую тоже надо потратить время. Именно для таких итераций идеально бы подошла горячая перезагрузка кода. Конечно, это не панацея, подойдет далеко не для всего, да и после перезагрузки иногда нужно пересоздать часть игрового мира, и это нужно учитывать. Но во многих вещах это может быть полезно и может сэкономить концентрацию внимания и кучу времени.

Требования и постановка задачи

Это минимальный набор требований, которым должна удовлетворять реализация. Забегая вперед, вкратце опишу то, что было реализовано дополнительно:

  • Перенос значений статических переменных в новый код (смотрите раздел «Перенос статических переменных», чтобы узнать, почему это важно)
  • Перезагрузка с учетом зависимостей (поменяли заголовочник -> пересобрали полпроекта все зависимые файлы)
  • Перезагрузка кода из динамических библиотек

Реализация

До этого момента я был совсем далек от предметной области, поэтому пришлось собирать и усваивать информацию с нуля.

На высоком уровне механизм выглядит так:

  • Мониторим файловую систему на предмет изменений в исходниках
  • Когда изменяется исходник, библиотека пересобирает его, используя команду компиляции, которой этот файл уже собирали
  • Все собранные объектники линкуются в динамически загружаемую библиотеку
  • Библиотека загружается в адресное пространство процесса
  • Все функции из библиотеки подменяют собой эти же функции в приложении
  • Значения статических переменных переносятся из приложения в библиотеку

Начнем с самого интересного — механизма перезагрузки функций.

Перезагрузка функций

Вот 3 более-менее популярных способа подмены функций в (или почти в) рантайме:

  • Трюк с LD_PRELOAD — позволяет собрать динамически загружаемую библиотеку с, например, функцией strcpy , и сделать так, чтобы при запуске приложение брало мою версию strcpy вместо библиотечной
  • Изменение PLT и GOT таблиц — позволяет «перегружать» экспортируемые функции
  • Function hooking — позволяет перенаправлять поток выполнения из одной функции в другую

Первые 2 варианта, очевидно, не подходят, поскольку работают только с экспортируемыми функциями, а мы не хотим помечать все функции нашего приложения какими-либо аттрибутами. Поэтому Function hooking — наш вариант!

Если вкратце, то hooking работает так:

  • Находится адрес функции
  • Первые несколько байт функции перезаписываются безусловным переходом в тело другой функции
  • .
  • Профит!
    В msvc для этого есть 2 флага — /hotpatch и /FUNCTIONPADMIN . Первый в начало каждой функции записывает 2 байта, которые не делают ничего, для последующей их перезаписи «коротким прыжком». Второй позволяет перед телом каждой функции оставить пустое место в виде nop инструкций для «длинного прыжка» в требуемое место, таким образом в 2 прыжка можно перейти из старой функции в новую. Подробнее о том, как это реализовано в windows и msvc, можно почтитать, например, тут.

К сожалению, в clang и gcc нет ничего похожего (по крайней мере под Linux и macOS). На самом деле это не такая большая проблема, будем писать прямо поверх старой функции. В этом случае мы рискуем попасть в неприятности, если наше приложение многопоточное. Если обычно в многопоточной среде мы ограничиваем доступ к данным одним потоком, пока другой поток их модифицирует, то тут нам нужно ограничить возможность выполнения кода одним потоком, пока другой поток этот код модифицирует. Я не придумал, как это сделать, поэтому реализация будет вести себя непредсказуемо в многопоточной среде.

Тут есть один тонкий момент. На 32-битной системе нам достаточно 5 байт, чтобы «прыгнуть» в любое место. На 64-битной системе, если мы не хотим портить регистры, понадобится 14 байт. Суть в том, что 14 байт в масштабах машинного кода — достаточно много, и если в коде есть какая-нибудь функция-заглушка с пустым телом, она скорее всего будет меньше 14 байт в длину. Я не знаю всей правды, но я провел некоторое время за дизассемблером, пока думал, писал и отлаживал код, и я заметил, что все функции выровнены по 16-байтной границе (debug билд без оптимизаций, не уверен насчет оптимизированного кода). А это значит, что между началом любых двух функций будет не меньше 16 байт, чего нам с головой хватит, чтобы «захукать» их. Поверхностное гугление привело сюда, тем не менее я точно не знаю, мне просто повезло, или сегодня все компиляторы так делают. В любом случае, если есть сомнения, достаточно просто объявить пару переменных в начале функции-заглушки, чтобы она стала достаточно большой.

Итак, у нас есть первая крупица — механизм перенаправления функций из старой версии в новую.

Поиск функций в скопмилированной программе

Теперь нам нужно как-то получить адреса всех (не только экспортированных) функций из нашей программы или произвольной динамической библиотеки. Это можно сделать достаточно просто, используя системные api, если из вашего приложения не вырезаны символы. На Linux это api из elf.h и link.h , на macOS — loader.h и nlist.h .

  • Используя dl_iterate_phdr проходимся по всем загруженным библиотекам и, собственно, программе
  • Находим адрес, по которому загружена библиотека
  • Из секции .symtab достаем всю информацию о символах, а именно имя, тип, индекс секции, в которой он лежит, размер, а также вычисляем его «реальный» адрес на основе виртуального адреса и адреса загрузки библиотеки

Здесь есть одна тонкость. При загрузке elf файла система не загружает секцию .symtab (поправьте, если неправ), а секция .dynsym нам не подходит, поскольку из нее мы не сможем выудить символы с видимостью STV_INTERNAL и STV_HIDDEN . Проще говоря, мы не увидим таких функций:

Читайте также:  Microsoft windows image component

и таких переменных:

Таким образом в 3-м пункте мы работаем не с программой, которую нам дала dl_iterate_phdr , а с файлом, который мы загрузили с диска и разобрали каким-нибудь elf парсером (либо на голом api). Так мы ничего не пропустим. На macOS процедура аналогичная, только названия функций из системных api другие.

После этого мы фильтруем все символы и сохраняем только:

  • Функции, которые можно перезагрузить — это символы типа STT_FUNC , расположенные в секции .text , имеющие ненулевой размер. Такой фильтр пропускает только функции, код которых реально содержится в этой программе или библиотеке
  • Статические переменные, значения которых нужно перенести — это символы типа STT_OBJECT , расположенные в секции .bss

Единицы трансляции

Чтобы перезагружать код, нам нужно знать, откуда брать файлы с исходным кодом и как их компилировать.

В первой реализации я читал эту информацию из секции .debug_info , в которой лежит отладочная информация в формате DWARF. Чтобы в каждую единицу трансляции (ЕТ) в рамках DWARF попала строка компиляции этой ЕТ, необходимо при компиляции передавать флах -grecord-gcc-switches . Сам же DWARF я парсил библиотекой libdwarf , которая идет в комплекте с libelf . Кроме команды компиляции из DWARF можно достать и информацию о зависимостях наших ЕТ от других файлов. Но я отказался от этой реализации по нескольким причинам:

  • Библиотеки достаточно увесистые
  • Разбор DWARF приложения, собранного из

500 ЕТ, с парсингом зависимостей, занимал чуть больше 10 секунд

10 секунд на старте приложения — слишком много. После недолгих раздумий я переписал логику парсинга DWARF на парсинг compile_commands.json . Этот файл можно сгенерировать, просто добавив set(CMAKE_EXPORT_COMPILE_COMMANDS ON) в свой CMakeLists.txt. Таким образом мы получаем всю нужную нам информацию.

Обработка зависимостей

Поскольку мы отказались от DWARF, нужно найти другой вариант, как обрабатывать зависимости между файлами. Парсить файлы руками и искать в них include ‘ы очень не хотелось, да и кто знает о зависимостях больше, чем сам компилятор?

В clang и gcc есть ряд опций, которые почти бесплатно генерируют так называемые depfile’ы. Эти файлы используют системы сборки make и ninja для разруливания зависимостей между файлами. Depfile’ы имеют очень простой формат:

Компилятор кладет эти файлы рядом с объектными файлами для каждой ЕТ, нам остается распарсить их и положить в хэшмапу. Итого парсинг compile_commands.json + depfiles для тех же 500 ЕТ занимает чуть больше 1 секунды. Для того, чтобы все заработало, нам нужно глобально для всех файлов проекта в опции компиляции добавить флаг -MD .

Здесь есть одна тонкость, связанная с ninja. Эта система сборки генерирует depfile’ы вне зависимости от наличия флага -MD для своих нужд. Но после их генерации она их переводит в свой бинарный формат, а исходные файлы удаляет. Поэтому при запуске ninja необходимо передать флаг -d keepdepfile . Также, по неизвестным мне причинам, в случае с make (с опцией -MD ) файл имеет название some_file.cpp.d , в то время как с ninja он называется some_file.cpp.o.d . Поэтому нужно проверять наличие обеих версий.

Перенос статических переменных

Пусть у нас есть такой код (пример весьма синтетический):

Мы хотим изменить функцию veryUsefulFunction на такую:

При перезагрузке в динамическую библиотеку с новым кодом, кроме veryUsefulFunction , попадет и статическая переменная static Singleton ins; , и метод Singletor::instance . Как следствие, программа начнет вызывать новые версии обеих функций. Но статическая ins в этой библиотеке еще не инициализирована, и поэтому при первом обращении к ней будет вызван конструктор класса Singleton . Мы этого, конечно, не хотим. Поэтому реализация переносит значения всех таких переменных, которые обнаружит в собранной динамической библиотеке, из старого кода в эту самую динамическую библиотеку с новым кодом вместе с их guard variables.

Тут есть один тонкий и в общем случае неразрешимый момент.
Пусть у нас есть класс:

Метод calledEachUpdate вызывается 60 раз в секунду. Мы меняем его, добавляя новое поле:

Если экземпляр этого класса располагается в динамической памяти или на стеке, после перезагрузки кода приложение скорее всего упадет. Аллоцированный экземпляр содержит только переменную m_someVar1 , но после перезагрузки метод calledEachUpdate будет пытаться изменить m_someVar2 , меняя то, что на самом деле не принадлежит этому экземпляру, что приводит к непредсказуемым последствиям. В этом случае логика по переносу состояния перекладывается на программиста, который должен как-то сохранить состояние объекта и удалить сам объект до перезагрузки кода, и создать новый объект после перезагрузки. Библиотека предоставляет события в виде методов делегата onCodePreLoad и onCodePostLoad , которые приложение может обработать.

Я не знаю как (и можно ли) разрешить эту ситуацию в общем виде, буду думать. Сейчас этот случай «более менее нормально» отработает только для статических переменных, там используется такая логика:

Это не очень корректно, но это лучшее, что я придумал.

В результате код будет вести себя непредсказуемо в случае, если в рантайме меняется набор и расположение (layout) полей в структурах данных. То же самое относится и к полиморфным типам.

Собираем все вместе

Как все это работает вместе.

  • Библиотека итерируется по заголовкам всех динамически загруженных в процесс библиотек и, собственно, самой программы, парсит и фильтрует символы.
  • Далее библиотека пытается найти файл compile_commands.json в директории приложения и в родительских директориях рекурсивно, и достает оттуда всю нужную информацию о ЕТ.
  • Зная путь к объектным файлам, библиотека загружает и парсит depfile’ы.
  • После этого вычисляется наиболее общая директория для всех файлов исходного кода программы, и начинается наблюдение за этой директорией рекурсивно.
  • Когда изменяется какой-то файл, библиотека смотрит, если ли он в хэшмапе зависимостей, и если есть, запускает в фоне несколько процессов компиляции измененных файлов и их зависимостей, используя команды компиляции из compile_commands.json .
  • Когда программа просит перезагрузить код (в моем приложении на это назначена комбинация Ctrl+r ), библиотека ждет завершения процессов компиляции и линкует все новые объектники в динамическую библиотеку.
  • Затем эта библиотека загружается в адресное пространство процесса функцией dlopen .
  • Из этой библиотеки загружается информация по символам, и все пересечение множества символов из этой библиотеки и уже живущих в процессе символов либо перезагружается (если это функция), либо переносится (если это статическая переменная).

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

Лично меня очень удивило отсутствие подобного решения для Linux, неужели никто в этом не заинтересован?

Источник

Оцените статью