Страницы

Поиск по вопросам

Показаны сообщения с ярлыком процесс. Показать все сообщения
Показаны сообщения с ярлыком процесс. Показать все сообщения

понедельник, 13 апреля 2020 г.

Как определить, жив ли процесс? Python 2.6, unix

#python #unix #процесс

                    
Вопрос тут появляется в похожем виде не впервые. Столкнулся со следующей проблемой:
нужно проверять не только существование процесса, но и то, что он не является зомби.
try:
    os.kill(pid, 0)
    return True
except OSError:
    return False

Вариант выше знаю, он не прокатывает с последним условием. Ставить внешние программы/модули
нельзя, все это происходит на разных машинах под линуксом и BSD, рутового доступа на
которые нету. Есть какие-нибудь варианты, как решить проблему?    


Ответы

Ответ 1



Можно чисто средствами баша ps aux | awk ' { print $2" "$8 } ' | grep -q "$pid Z" где $pid это pid вашего процесса. В случае если процесс зомби, то результат этой команды будет равен нулю, т.е. полное совпадение.

суббота, 11 апреля 2020 г.

Смена текущего каталога из дочернего процесса

#ruby #процесс

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

Что то вроде:

# test.rb
`cd /new/dir`


Желаемый результат:

$ pwd
/my/test/dir
$ ruby test.rb && pwd
/new/dir

    


Ответы

Ответ 1



краткий ответ: это невозможно. чуть более длинный ответ (с некоторыми упрощениями и без кучи оговорок): текущий каталог — это свойство процесса. свойство это наследуется «дочерними» процессами от «родительского». когда вы в оболочке выполняете, например, команду ruby ..., оболочка запускает «дочерний« процесс (делает fork), который уже и «загружает в себя» бинарный файл /usr/bin/ruby. этот «дочерний» процесс (под управлением загруженного бинарника), конечно, может изменить своё свойство — текущий каталог, и даже передать его «по наследству потомкам». но на «родительский» процесс он никакого влияния оказать не может.

Ответ 2



сменить директорию в окне консоли можно, если устроит создание дочернего шелла # chdir.rb Dir.chdir ARGV[0] exec "bash" $ pwd /home/me/dir1/dir2 $ ruby chdir.rb .. $ pwd /home/me/dir1

воскресенье, 1 марта 2020 г.

Что происходит с памятью при вызове exec() на уровне ядра?

#linux #процесс


Вопрос теоретический. fork() делает копию процесса. Известно, что родительский процесс
имеет собственное адресное пространство. Дочерний процесс, фактически, до какого-то
момента может работать с адресным пространством своего родителя. Этот момент - запись
в адресное пространство. Таким образом дочерний процесс в режиме "только чтение" может
в полной мере руководствоваться родительским адресным пространством. Если производится
запись, то адресное пространство копируется (copy-on-write [COW]). Возникает несколько
вопросов: 


Что будет со скопированным адресным пространством, если будет вызван exec()?
Если после fork() вызвать exec(), то новый исполняемый код создает свое собственное
адресное пространство? 
Что будет с таблицей страниц дочернего процесса после вызова exec()?

    


Ответы

Ответ 1



Рассматривать что происходит с памятью при вызове exec() в отрыве от остальной подсистемой управления пямятью — неполноценно и описать этот процесс можно только в общих словах. А по всей данной подсистеме можно написать целую книгу (и несколько уже написаны), но я всё же попытаюсь выделить основные моменты. Немного о структурах связанных с управлением памятью процесса Кратко опишу назначение основных структур связанных с управлением памятью процесса. Структуры связанные с управлением виртуальным АП. task_struct — дескриптор процесса mm_struct — адресное пространство процесса vm_area_struct — отдельный сегмент памяти процесса со своим набором атрибутов (rwx), можно думать о нём как о неком регионе отображённом в память mmap ()'ом: он может быть и частью файла (исполняемого или обычного) и простым анонимным участком памяти. Список можно посмотреть, например в /proc//maps. Структуры связанные с трансляцией адресов и физической памятью: pgd_t и pmd_t (а также p4d и pud) — системно-зависимые типы для записей в глобальной директории страниц (Page Global Directory) и промежуточной директории страниц (Page Middle Directory), если таковая есть (на простом x86 таковой нет). p4d и pud — это дополнительные типы в новых ядрах для пятиуровневой и четырёхуровневой адресации. pte_t — системно-зависимый тип Записи в таблице страниц (Page Table Entries). На x86 это, как и pgd_t 32-битный тип с аналогичным названием. struct page — системно-независимая структура представляющая страницу физической памяти. Все они постоянно хранятся в памяти в массиве mem_map. Если кратко, то эти структуры взаимосвязаны следующим образом: task_struct.mm ссылается на mm_struct, связанный с процессом. На один mm_struct может ссылаться несколько task_struct (так в частности реализованы потоки) mm_struct.mmap в свою очередь ссылается на двусвязный список vm_area_struct, связанных с процессом. mm_struct.pgd хранит адрес глобальной директории страниц pgd_t связанной с процессом. На x86 он фактически загружается в CR3 при смене контекста. vm_area_struct.mm — указатель на mm_struct к которому принадлежит данный сегмент. vm_area_struct.next и vm_area_struct.prev — указатели на предыдущий и следующий элемент в двусвязном списке. Для pte_t и pgd_t можно получить соответствующую структуру struct page с помощью макросов и pte_page() и pgd_page() соответственно. Немного о том, как работает COW При создании нового процесса fork ()'ом цикл проходится по всем связанным с ним vm_area_struct и помечает все доступные на запись страницы (pte_t), доступными только на чтение. А в соответствующей struct page увеличивается счётчик ссылок на страницу. Когда процесс пытается записать в такую страницу, происходит прерывание, далее обработчик (спустившись на несколько функций по стеку вызовов) определяет, что хотя прерывание произошло на странице на которой запрещена запись (согласно pte_t), эта страница относится к сегменту, в котором она разрешена (согласно vm_area_struct). Таким образом определяется, что это одна из COW-страниц и происходит копирование. После чего уменьшается счётчик ссылок исходной страницы (в struct page) и, если он достиг нуля, снова разрешается запись в неё. Что происходит с адресным пространством при execve() Сначала exec() создаёт новое АП (mm_struct) частично его инициализирует (например создаёт стек), А потом пробует подсунуть файл поочерёдно каждому из модулей поддержки форматов (например ELF) пока один из них не сможет его загрузить. Модуль в свою очередь сначала проводит частичную проверку формата и также частичную инициализацию АП, а затем, когда убедится, что формат выбран правильно и скорей всего удастся загрузить данный файл, происходит подмена старого АП новым и последующая подчистка старого. В частности она включает: Уменьшение количества пользователей АП (mm_struct.users), если оно достигло нуля, то: В цикле обходятся все vm_area_struct и для каждой происходит рекурсивная итерация по каталогу страниц в результате счётчики ссылок всех ассоциированных страниц (struct page) уменьшаются аналогично тому как это было описано для COW. После этого в другом цикле обходятся все vm_area_struct и записываются несохранённые данные из грязных страниц mmap-файлов. Уменьшается количество ссылок на АП (mm_struct.count) и если оно достигло нуля (кроме процессов структура может использоваться другими подсистемами ядра), то она полностью удаляется. В случае успешного завершения модуль формата продолжит инициализацию АП, а затем произойдёт передача управления процессу. Стоит заметить, что операция подмены АП(вызов flush_old_exec()) — это точка невозвращения, т.е. после оной exec () уже не сможет вернуть одну из документированных ошибок; и в случае сбоя весь процесс будет аварийно завершён по сигналу, например, SIGSEGV. Односложные ответы на конкретные вопросы Что будет со скопированным адресным пространством, если будет вызван exec()? Оно будет замещено другим, созданным exec (). Если после fork() вызвать exec(), то новый исполняемый код создает свое собственное адресное пространство? Да. Что будет с таблицей страниц дочернего процесса после вызова exec()? Она также будет замещена новой. Страницы не используемые другими будут добавлены в список свободных. Дальнейшее чтение: Understanding The Linux Virtual Memory Manager — Книга описывает довольно старое ядро, но отличия в основном косметические, а основные принципы не изменились.

среда, 26 февраля 2020 г.

Структура сегментов в адресном пространстве процесса

#память #процесс


|----------------------------Kernel Space------------------------------|  0xFFFFFF
                                                                 
|                                                                      |
|                                                                      |
|                                                                      |
|↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓Stack↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓|
|                                                                      |
|                                                                      |
|                                                                      |
|↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓Memory mapping segment↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓|
|                                                                      |
|                                                                      |
|                                                                      |
|↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑Heap↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑|
|                                                                      |
|                                                                      |
|-----------------------------BSS  segment-----------------------------|
|-----------------------------Data segment-----------------------------|
|-----------------------------Text segment-----------------------------|
|                                                                      |
|---------------------------------OS-----------------------------------|
|________________________________BIOS__________________________________| 0x000000 


Вопросы:

1) Как устроен Memory mapping segment?

2) Есть ли сегмент для констант?

3) В С++ есть и Heap и Free Store, или Heap интерпретируется как Free Store (если
да, то как размещен?) ?

4) Есть сегменты(с показанных выше) которые могут отсутствовать?

5) Есть замечания к указанной структуре памяти?
    


Ответы

Ответ 1



Константы обычно размещаются в текстовом сегменте, т.к. он защищен от записи. В остальном картинка условно соответствует большинству реализаций с виртуальной памятью. Также следует иметь в виду, что между показанными сегментами возможны "дыры" (в смысле пространства виртуальных адресов). Распределение памяти для конкретных Linux программ на практике можно посмотреть в файле /proc/{PID}/maps В качестве примера, вот такая программка и результат ее выполнения: avp@avp-ubu1:hashcode$ cat t-maps.c #include #include #include static int data = 22; int main (int ac, char *av[]) { const char *p = "xaxa-xaxaxaxax"; printf("main: %p p: %p &p: %p &data: %p\n", main, p, &p, &data); char str[100]; sprintf(str, "cat /proc/%d/maps", (int)getpid()); system(str); } avp@avp-ubu1:hashcode$ g++ t-maps.c && ./a.out main: 0x56352bf8278a p: 0x56352bf828b8 &p: 0x7ffff853a718 &data: 0x56352c183010 56352bf82000-56352bf83000 r-xp 00000000 08:01 1179691 /home/avp/hashcode/a.out 56352c182000-56352c183000 r--p 00000000 08:01 1179691 /home/avp/hashcode/a.out 56352c183000-56352c184000 rw-p 00001000 08:01 1179691 /home/avp/hashcode/a.out 56352ce80000-56352cea1000 rw-p 00000000 00:00 0 [heap] 7fd21e33c000-7fd21e356000 r-xp 00000000 08:01 2159140 /lib/x86_64-linux-gnu/libpthread-2.27.so 7fd21e356000-7fd21e555000 ---p 0001a000 08:01 2159140 /lib/x86_64-linux-gnu/libpthread-2.27.so 7fd21e555000-7fd21e556000 r--p 00019000 08:01 2159140 /lib/x86_64-linux-gnu/libpthread-2.27.so 7fd21e556000-7fd21e557000 rw-p 0001a000 08:01 2159140 /lib/x86_64-linux-gnu/libpthread-2.27.so 7fd21e557000-7fd21e55b000 rw-p 00000000 00:00 0 7fd21e55b000-7fd21e55e000 r-xp 00000000 08:01 2159128 /lib/x86_64-linux-gnu/libdl-2.27.so 7fd21e55e000-7fd21e75d000 ---p 00003000 08:01 2159128 /lib/x86_64-linux-gnu/libdl-2.27.so 7fd21e75d000-7fd21e75e000 r--p 00002000 08:01 2159128 /lib/x86_64-linux-gnu/libdl-2.27.so 7fd21e75e000-7fd21e75f000 rw-p 00003000 08:01 2159128 /lib/x86_64-linux-gnu/libdl-2.27.so 7fd21e75f000-7fd21e946000 r-xp 00000000 08:01 2159125 /lib/x86_64-linux-gnu/libc-2.27.so 7fd21e946000-7fd21eb46000 ---p 001e7000 08:01 2159125 /lib/x86_64-linux-gnu/libc-2.27.so 7fd21eb46000-7fd21eb4a000 r--p 001e7000 08:01 2159125 /lib/x86_64-linux-gnu/libc-2.27.so 7fd21eb4a000-7fd21eb4c000 rw-p 001eb000 08:01 2159125 /lib/x86_64-linux-gnu/libc-2.27.so 7fd21eb4c000-7fd21eb50000 rw-p 00000000 00:00 0 7fd21eb50000-7fd21eb56000 r-xp 00000000 08:01 3670234 /usr/lib/x86_64-linux-gnu/libgtk3-nocsd.so.0 7fd21eb56000-7fd21ed55000 ---p 00006000 08:01 3670234 /usr/lib/x86_64-linux-gnu/libgtk3-nocsd.so.0 7fd21ed55000-7fd21ed56000 r--p 00005000 08:01 3670234 /usr/lib/x86_64-linux-gnu/libgtk3-nocsd.so.0 7fd21ed56000-7fd21ed57000 rw-p 00006000 08:01 3670234 /usr/lib/x86_64-linux-gnu/libgtk3-nocsd.so.0 7fd21ed57000-7fd21ed7e000 r-xp 00000000 08:01 2159121 /lib/x86_64-linux-gnu/ld-2.27.so 7fd21ef5a000-7fd21ef5e000 rw-p 00000000 00:00 0 7fd21ef7e000-7fd21ef7f000 r--p 00027000 08:01 2159121 /lib/x86_64-linux-gnu/ld-2.27.so 7fd21ef7f000-7fd21ef80000 rw-p 00028000 08:01 2159121 /lib/x86_64-linux-gnu/ld-2.27.so 7fd21ef80000-7fd21ef81000 rw-p 00000000 00:00 0 7ffff851c000-7ffff853d000 rw-p 00000000 00:00 0 [stack] 7ffff8563000-7ffff8566000 r--p 00000000 00:00 0 [vvar] 7ffff8566000-7ffff8568000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] avp@avp-ubu1:hashcode$

четверг, 13 февраля 2020 г.

Как узнать путь к файлу по имени процесса и имени владельца?

#windows #c_sharp #процесс


На терминальном сервере человек 10 запускают приложение, пусть это будет CALC.exe,
и естетсвенно, в процессах 10 ОДИНАКОВЫХ процессов.

Здесь мне подсказали, как узнать путь к файлу нужного процесса.

А как сделать тоже самое, только если пользователя зовут ВАСЯ, то процесс запущенный
ВАСЕЙ и находился?
    


Ответы

Ответ 1



Самый простой вариант с помощью WMI: string processName = "calc.exe"; string currentUser = WindowsIdentity.GetCurrent().Name.Split('\\')[1]; string query = "Select * from Win32_Process Where Name = \"" + processName + "\""; ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); ManagementObjectCollection processes = searcher.Get(); foreach (ManagementObject proc in processes) { string owner; string[] argList = new string[] { string.Empty }; int returnVal = Convert.ToInt32(proc.InvokeMethod("GetOwner", argList)); if (returnVal == 0) owner = argList[0]; else continue; if (owner != currentUser) continue; // Вот тут-то и остался только нужный процесс! string path = proc["ExecutablePath"].ToString(); }

Ответ 2



На WinApi проблема решалась еще в первом вопросе) Поиск по msdn выдал сразу: Получаем токен процесса по хендлу: OpenProcessToken(...) SID пользователя - в информации о токене: GetTokenInformation(...) @kirelagin: Оригинал с мсдн: BOOL WINAPI OpenProcessToken( __in HANDLE ProcessHandle, __in DWORD DesiredAccess, __out PHANDLE TokenHandle ); В c#: [DllImport("Advapi32.dll", EntryPoint = "OpenProcessToken")] private static extern bool OpenProcessToken(int ProcessHandle, int DesiredAccess, int* TokenHandle);

воскресенье, 9 февраля 2020 г.

Регистры (теоретический вопрос)

#ассемблер #память #асинхронность #процесс #теория


Здравствуйте, извиняюсь за возможно глупый вопрос, но скажите пожалуйста где располагаются
регистры eax, ebx, ecx, edx, edi, esi, в оперативной памяти или процессоре?

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


Ответы

Ответ 1



регистры располагаются, конечно, в процессоре (если речь о современных распространённых процессорах). попеременно же используются они разными процессами благодаря механизму многозадачности. в грубом приближении: внутри процессора есть таймер, который время от времени посылает процессору сигнал («прерывание»), при получении которого процессор сохраняет текущее содержимое всех регистров в стек (находится в оперативной памяти, обычно каждый процесс имеет собственный стек; а сохраняются туда регистры не только с данными, но и со всякой контрольно-управляющей информацией, типа ip — instruction pointer — адресом следующей выполняемой команды) и передаёт управление по адресу обработчика данного прервывания (обработчик обычно реализован в ядре операционой системы). обработчик выбирает, какой процесс следует запустить следующим (какому процессу отдать очередной «квант времени»), и даёт процессору команду «загрузить в регистры то, что сохранённо там-то». восстановленный же из стека процесс продолжает работу «как ни в чём не бывало», до следующего срабатывания таймера.

Ответ 2



Регистры в процессоре. Многозадачность - фича ОС, которая сохраняет контекст процесса, включая регистры. Так и получается что один набор регистров вполне досаточен для многих процессов.

среда, 29 января 2020 г.

Можно ли средствами Java убить дочерние процессы процесса, созданного с помощью ProcessBuilder?

#java #jvm #процесс #multiprocessing


Если создать процесс 

ProcessBuilder builder = new ProcessBuilder("command");
final Process process = builder.start();


то его можно будет убить с помощью: process.destroy();

Но что, если этот command наплодит кучу других процессов? process.destroy(); уже
будет не в силах убить их. И они останутся в памяти.

При этом, если из командной строки сделать Ctrl+C, то дочерние процессы тоже завершатся.

В сети много вопросов на эту тему (большинство из них старые) и почти все ответы
говорят о том, что это невозможно сделать средствами JVM - нужно обращаться к ОС. Решил
задать вопрос, в надежде на то, что это всё же стало возможным с появлением Java 8.
Хочется получить решение, не зависимое от ОС.

Возможно ли на сегодняшний день средствами Java убить дочерние процессы процесса,
созданного с помощью ProcessBuilder, не манипулируя напрямую с командами ОС? Если возможно,
то как это реализовать? Если нет, то ожидается ли такая возможность в Java 9?

UPDATE

Хочу ещё раз выделить то, что я не ищу решения, зависящие от ОС. По этой ссылке можно
прочитать о том, как искать PID процесса в Unix и Windows. Потом можно будет обратиться
к терминалу с соответствующей командой для "убийства" процесса. 

Это не является темой данного вопроса.
    


Ответы

Ответ 1



В версиях Java до 8й включительно инструментарий для работы с процессами был довольно скудным. Но если ознакомиться, с JEP 102: Process API Updates (который реализуется в рамках Java 9), то мы увидим, что Brian Goetz говорит нам о следующих вещах: Возможность получить pid процесса JVM и pid-ы процессов, запущенных средствами API. Возможность получить список запущенных в системе процессов, включая их pid, состояние, наименование и, возможно, потребление ресурсов. Возможность взаимодействовать с деревьями процессов, а именно прекращать работу целого дерева. Возможность взаимодействовать с сотнями дочерних процессов, возможно, мультиплексируя потоки вывода и ошибок, чтобы избежать создания отдельной нити (thread) на каждый процесс. Все эти радости уже можно потрогать в 9ке: см. интерфейс ProcessHandle: long getPid() static Stream allProcesses() и ProcessHandle.Info info() Stream descendants()

Ответ 2



Если речь идет о "популярных" ОС для Java (Windows & unix-like), то на первой можно запустить программу taskkill/PID , а на вторых - kill-9 . На юниксе, кроме того, можно отправить сигнал группе процессов (process group id равен - процесса-родоначальника группы. Или воспользоваться библиотекой, дергающей нативные методы, типа Posix for Java (впрочем, для метода kill достаточно простого JNI вызова. Но средствами именно Java, да без сторонних библиотек, насколько я знаю, нет. Правда, говорят, что у Process так просто pid не получишь, но вот можно через Reflection достать приватное поле UnixProcess'а pid.. :) В 9-ой версии OpenJDK Process имеет метод getPid(), так что, теперь вышла нам всем поблажка в плане получения pid. Однако, никаких переносимых методов для управления группой процессов пока не просматривается.

Ответ 3



Кроссплатформенного решения нету. Придётся писать для каждой ОС самому. Не так всё просто, по-этому вряд ли кто-то даст законченное решение. Мы можем только дать какие-то подсказки, пути к решению задачи. Unix Сначала надо получить PID нашего процесса. /** * Получить строку - pid программы - Java VM */ public static String getPid() throws IOException,InterruptedException { Vector commands=new Vector(); commands.add("/bin/bash"); commands.add("-c"); commands.add("echo $PPID"); ProcessBuilder pb=new ProcessBuilder(commands); Process pr=pb.start(); pr.waitFor(); if (pr.exitValue()==0) { BufferedReader outReader=new BufferedReader(new InputStreamReader(pr.getInputStream())); return outReader.readLine().trim(); } else { System.out.println("Error while getting PID"); return ""; } } С другой стороны java.lang.Process - абстрактный класс, конкретная реализация зависит от ОС. На Linux это java.lang.UnixProcess, у которой есть приватное поле pid. Используя рефлексию можно запросто получить поле: public static long getPidOfProcess(Process p) { long pid = -1; try { if (p.getClass().getName().equals("java.lang.UNIXProcess")) { Field f = p.getClass().getDeclaredField("pid"); f.setAccessible(true); pid = f.getLong(p); f.setAccessible(false); } } catch (Exception e) { pid = -1; } return pid; } Дальше необходимо получить список подпроцессов. Есть комманда pstree ${pid}. Можно выполнить команду из Java Process p = Runtime.getRuntime().exec("pstree ${pid}"); Затем спарсить список и вытащить PID'ы всех процессов. Потом используя Runtime.getRuntime().exec() убить все процессы по PID'ам, если надо. Windows Для получения PID'а можно сделать что-то такое. Тут сложнее. Я знаю, что можно получить список запущенных процессов. Process p = Runtime.getRuntime().exec("cmd /c tasklist"); StringWriter writer = new StringWriter(); IOUtils.copy(p.getInputStream(), writer); String theString = writer.toString(); Но вопрос как найти зависимости между процессами не ясен. Как минимум, можно выполнить tasklist и отфильтровать список по имени процесса. Процесс с большим PID вероятно и есть ваш процесс. Так вы получите PID вашего главного процесса. Можно попробовать запустить PowerShell скрипт для получения списка процессов (а потом отфильтровать по parent id). Такая команда в шеле: gwmi win32_process |select ProcessID,ParentProcessID,Name, @{l="Username";e={$_.getowner().user}}|where {$_.Username -ne "SYSTEM"} | where {$_.Username -ne "LOCAL SERVICE"} | where {$_.Username -ne "NETWORK SERVICE"} | where {$_.Username -ne $null} |Sort-Object ProcessID | ft -AutoSize Даст что-то такое: ProcessID ParentProcessID Name Username --------- --------------- ---- -------- 180 4536 chrome.exe Suvitruf 396 5272 slack.exe Suvitruf 1488 1040 taskeng.exe Suvitruf 1504 4008 BatteryLife.exe Suvitruf 1540 180 chrome.exe Suvitruf 1704 180 chrome.exe Suvitruf 2084 180 chrome.exe Suvitruf 2404 5272 slack.exe Suvitruf 2408 5272 slack.exe Suvitruf Вам надо понять как эту команду выполнить с использованием Runtime.getRuntime().exec(). После этого распарсить ответ и получить список PID'ов процессов. Для их убийства вызывать: String cmd = "taskkill /F /PID " + tokill; Runtime.getRuntime().exec(cmd);

вторник, 28 января 2020 г.

Процессы и нити в Линукс

#linux #многопоточность #процесс


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


Ответы

Ответ 1



Определение Раз уж говорим о *nix системах, то не лишним будет опираться на определения POSIX (вольный перевод): Thread (досл. нить, она же поток¹) — это один из потоков выполнения (flow control) в составе процесса. У каждой нити есть свой thread ID, приоритет и политика планировщика, errno, своё обособленное хранилище формата ключ/значение, и необходимые ресурсы, чтобы поддерживать поток выполнения. Любой объект, адрес которого может определить нить будет доступен всем нитям данного процесса, включая, но не ограничиваясь, статическими переменными, памятью, полученным посредством malloc(), другим областям памяти, к которым возможен прямой доступ по адресу, и автоматическим переменным. Процесс — адресное пространство с одной или более нитью, исполняющейся в контексте оного, а также необходимые ресурсы для данных нитей. Замечание: многие системные ресурсы разделяются (используются совместно) разными нитями одного процесса. В том числе различные идентификаторы (PID, PPID, PGID, SSID, различные SUID'ы и SGID'ы), текущий рабочий каталог, корневой каталог, umask и файловые дескрипторы. Отсюда вырисовываются следующие ассоциации ресурсов... У процесса есть: Адресное пространство (включая код, а также статические и динамические данные программы) Одна или более нить Таблица файловых дескрипторов Другие системные ресурсы и идентификаторы При этом у каждой нити процесса также есть: Поток выполнения, на практике это значит: Свой стек и, как следствие, свои локальные переменные. Свои регистры процессора ID нити Приоритет в планировщике errno и, возможно, некоторые другие переменные локальные для нити. Особенности реализации потоков в Linux. Фактически, потоки в Linux реализованы, как «легковесные процессы». Другими словами со стороны ядра linux нет чёткого разграничения между оными: все они представляются в ядре, как задачи task_struct, при этом, например, task->mm указывает на дескриптор адресного пространства (mm_struct), а task->files на таблицу файловых дескрипторов (files_struct) и для потоков одного процесса оба эти указателя будут просто указывать на один объект. ИМХО прежде всего это сделано в силу исторических причин, хотя такая реализация и не лишена своей красоты. И всё бы ничего, но это породило просто невообразимую терминологическую кашу. Например, со стороны пользовательского пространства идентификатор процесса (то что возвращает getpid(), он должен быть одинаковый для всех потоков процесса) называется PID; но на стороне ядра под pid'ом подразумевается идентификатор задачи, а вызов getpid() возвращает то что называется tgid (thread group ID, ID группы потоков). Но при этом через /proc экспортируется информация именно в терминах ядра. Также такая реализация предполагает определённые ухищрения, частично на стороне ядра, частично на стороне пользовательского пространства, например, системный вызов setuid(2) в linux устанавливает только EUID потока, поэтому приходится прибегать к сложным манипуляциям в обёртке в libc, чтобы добиться поведения соответствующего POSIX и, как следствие, возникают проблемы с реализацией этой функции в языках независимых от Си, например Rust или Go. Но ведь у нитей тоже есть PID и свойства, как у обычных процессов, Не совсем так: единственное, что у них есть — это приоритет и политика в планировщике... всё остальное — баги и/или особенности реализации. и порождать другие нити они тоже могут. Да, но здесь стоит заметить, что в отличии от порождения процесса, «родителем» новой нити становится исходный процесс, а не тот что породил нить. ¹я предпочитаю термин «поток», но дабы не разгребать терминологическую путаницу с flow буду использовать «нить» в данном разделе

Ответ 2



Термин «поток» (thread, нить) является краткой формой Поток выполнения процесса. Поток выполнения — это последовательность исполняемых команд, которые можно запланировать для запуска на ЦП. Потоки также имеют некоторое состояние и хранят некоторые локальные переменные. Нити процесса разделяют его программный код, глобальные переменные и системные ресурсы, но каждая нить имеет свои программный счетчик, содержимое регистров и стек Процесс — совокупность взаимодействующих нитей и выделенных ему ресурсов. Вот картинка для наглядности.

пятница, 24 января 2020 г.

C# использование функции kernel32 CreateProcess

#c_sharp #winapi #процесс


Есть две программы, написанные на с#. Обе - консольные приложения, в каждой создается
форма (System.Windows.Forms.Form).
Первая программа в процессе своей работы создает/уничтожает вторую программу. Вот
код создания процесса второй программы:

var proc = new System.Diagnostics.Process
{
    StartInfo = new System.Diagnostics.ProcessStartInfo
    {
        FileName = exe,
        Arguments = args
    },
    EnableRaisingEvents = true
};
proc.Start();


Т.е. я имею консоль первой программы + окно первой программы + несколько таких же
пар для каждого запущенного экземпляра второй программы.
Все работает, как надо. Но мне жутко надоело, что новые процессы постоянно перехватывают
фокус на себя (при создании). Нашел вот такое решение (ответ benrwb). Проверил - фокус
больше не перехватывает. Программы запускаются, только вот 


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


Я посмотрел описание функции CreateProcess, ее флагов. Попытался добавить флаги DETACHED_PROCESS,
CREATE_NEW_CONSOLE и т.д. но методом тыка ничего путного не получилось. 

Как из программы c# запускать абсолютно несвязанные процессы (как если бы я вручную
запускал exe-файл) и при этом чтобы новые окна вообще не перехватывали фокус? (не надо
предлагать возвращать перехваченный новым окном фокус обратно - это не подходит)

UPD 1

Вопрос такой: как из программы, написанной на c#, сделать запуск другой программы,
написанной на c#, аналогично приведенному выше коду, но с помощью функции из kernel32.dll
CreateProcess. У меня есть доступ к исходным кодам обоих программ.

UPD 2

Следующий код создает новый процесс, не перехватывая фокус, но с консолью родительского
процесса. При закрытии созданного процесса закрывается и главный процесс. Если добавить
флаги CREATE_NEW_CONSOLE, DETACHED_PROCESS или CREATE_NEW_PROCESS_GROUP, результат
не меняется.

STARTUPINFO si = new STARTUPINFO();
si.cb = (UInt32)Marshal.SizeOf(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNOACTIVATE;

UInt32 dwCreationFlags = ABOVE_NORMAL_PRIORITY_CLASS;

PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

CreateProcess(name, path + " " + inprms, IntPtr.Zero, IntPtr.Zero, false, dwCreationFlags,
IntPtr.Zero, System.IO.Path.GetDirectoryName(path), ref si, out pi);


UPD 3

Нашел такое "решение" средствами c#:

// основная программа - запуск дочерней программы
var proc = new System.Diagnostics.Process
{
    StartInfo = new System.Diagnostics.ProcessStartInfo
    {
        FileName = exe,
        Arguments = args,
        UseShellExecute = false,
        WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden
    },
    EnableRaisingEvents = true
};
proc.Start(); 

// дочерняя программа - событие загрузки главного окна
Load += (s, e) =>
{
    Show();
};     


При таком подходе у дочерних программ нет консоли, весь вывод направляется в консоль
главного процесса. Закрытие любого из процессов никак не влияет на другие процессы.
Не знаю, почему, но Show() не перехватывает фокус (как мне и нужно). 
Если написать UseShellExecute = true, то консоль так же будет одна, но Show() будет
перехватывать фокус на дочернее окно. Если кто-нибудь мне объяснит, почему, буду признателен.

UPD 4

Так же хотелось бы узнать, как же все-таки это можно сделать через CreateProcess().

UPD 5

После некоторого времени отладки оказалось, что описанный выше пример работает непредсказуемо
(то фокусит, то нет). Испробовав разные способы я нашел таки вариант, который меня устроил:

// основная программа - запуск дочерней программы
var proc = new System.Diagnostics.Process
{
    StartInfo = new System.Diagnostics.ProcessStartInfo
    {
        FileName = exe,
        Arguments = args,
        WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden
    },
    EnableRaisingEvents = true
};
proc.Start(); 

// дочерняя программа - при создании главного окна
using (Window = new MyWindow())
{
    Window.Show();
    Window.SendToBack();

    ConsoleVisible(WINDOW_STYLE.SW_SHOWMINNOACTIVE);

    Application.Run(Window);
} 

public static void ConsoleVisible(UInt16 WINDOW_STYLE)
{
    var handle = GetConsoleWindow();
    ShowWindow(handle, WINDOW_STYLE);
}

[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, UInt16 nCmdShow);


Запуск процесса с WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden скрывает
как само окно приложения, так и его консоль. В запускаемом приложении Show() восстанавливает
окно формы, но! не фокусит его, а только размещает поверх всех окон. С помощью SendToBack()
оно отправляется на задний план, фокус все это время не тронут. Консоль в это время
спрятана и нигде не отображается. Чтобы ее вернуть, вызываем WinApi с флагом SW_SHOWMINNOACTIVE.
Консоль появляется на панели задач в свернутом состоянии. Интересно то, что если использовать
флаг SW_SHOWNOACTIVATE, то консоль восстанавливается и автоматически фокусится, что
мне не подходит.

Благодарю всех, кто помогал.
    


Ответы

Ответ 1



По той же ссылке, что вы кинули есть более лаконичное решение: public class MyClass { [DllImport("user32.dll")] static extern bool SetForegroundWindow(IntPtr hWnd); public void doProcess(string filename, string arguments){ using (Process proc = new Process()) { proc.StartInfo.FileName = filename; proc.StartInfo.Arguments = arguments; proc.Start(); SetForegroundWindow(proc.MainWindowHandle); } } } Новые процессы просто переносим на задний план. Если у вас есть доступ к коду приложений, которые вы запускаете, то можете их доработать. Например, что бы можно было передавать какие-то аргументы и при запуске само приложение уходило на задний план или сворачивалось. А еще, вроде, можно запускать программу в свернутом состоянии через CMD: start /min "" "C:\Windows\notepad.exe"

четверг, 23 января 2020 г.

bash: синхронизация скрипта с параллельно запущенными им дочерними процессами. Как / можно ли?

#bash #асинхронность #процесс


Вопрос по bash

Хочу запустить неск. экземпляров приложения(ий) параллельно из сценария для bash.
Нужно что-то вроде синхронизации. 

Запускаю через & . При этом получается, что запускающий скрипт не знает о дальн.
"судьбе" запущенного процесса. Например, хотелось бы, использовать:


Ожидание. После запуска всех нужных (параллельно запущенных) приложений, запустивший
их скрипт ждал, пока все они не завершатся и/или какие-н. из них. После окончания,
напр., скрипт м. выдать сообщения, что операция завершена.
Прерывание. Если из скрипта запущено много процессов, через диспетчер процессов неудобно
их принудительно завершать (в случае, когда ждать надоедает). Если бы дочерний процесс
был запущен последовательно (без &), то закрыв окно консоли, из которой был запущен
скрипт, завершились (принудительно) и все порождённые им процессы. Хотелось бы получить
что-то вроде того и для параллельно (через &) запущенных процессов. Напр., скрипт спрашивает,
"завершить ли дочерние процессы?", ввожу что-л. в консоли и все параллельно запущенные
процессы принудительно завершаются.


ВОПРОС: как вообще по-нормальному (без изобретения велосипедов) это в bash можно
сделать и вообще, можно ли?



По запросу @alexander-barakin - неработающий wait:

Файл: inv_3.BASh

#!/bin/bash

      declare Path="$(dirname "${0}")"; Path="${Path%/}/";
      declare Data="${Path}t2.data.fifo";
      declare Can_write="${Path}t2.can.fifo";


  trap "echo _ > \"${Can_write}\"; " Usr1;

  aValue=$BASHPID;
  bash "${Path}sub_3.BASh" $aValue &

  wait;

  echo ;
  echo "    JOBS:";
  jobs -pr;
  echo ;

  echo "Завершено."




Файл: sub_3.BASh

#!/bin/bash

  declare theRecievers="${1}";

      declare Path="$(dirname "${0}")"; Path="${Path%/}/";
      declare Data="${Path}t2.data.fifo";
      declare Can_write="${Path}t2.can.fifo";

  trap "echo $BASHPID: END" Exit;

  kill -s Usr1 ${theRecievers};

  i=2;
  while ((i--)); do
    while ! read < "${Can_write}"; do
      kill -s Usr1 ${theRecievers}; 
    done;
  done;




Воспроизведение:


Создаёте файлы inv_3.BASh, sub_3.BASh
В том же каталоге создаёте pipe: t2.can.fifo, t2.data.fifo
В консоли: bash "inv_3.BASh"; echo $?;


Ожидаемое (от wait) поведение:

Сценарий, в котором вызывается wait не выполняет команды после wait, пока не завершится
доч. процесс, т. е., вывода "... JOBS: ..." вообще не д. быть до завершения доч. процесса.

Вижу:

JOBS:
    14066



Открываю диспетчер процессов: процесс с pid 14066 есть.
Значение pid, естеств., каждый раз - разное.

    


Ответы

Ответ 1



ожидание завершения всех дочерних процессов осуществляется с помощью команды wait. перехват сигнала sigint (который передаётся процессу при нажатии ctrl+c) и завершение всех дочерних процессов неплохо описано, например здесь.

среда, 22 января 2020 г.

Можно ли узнать кто прячется за ServiceHost?

#c_sharp #net #windows #процесс


При работе с пакетом офиса через Microsoft.Office.Interop в процессах создается офисные
приложения.

Например, работая с Word создастся процесс Word'a, а сам интерфейс будет невидимым.

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

Пробовал родительский PID получать, так вот он относится к ServiceHost=> я не могу
сравнить его с PID своей программы, что бы удостоверится, что я породил данный процесс.
    


Ответы

Ответ 1



Проще всего - выбрать сервисы через WMI (System.Management.dll) и отфильтровать по процессу, примерно так: using System.Diagnostics; using System.Management; ManagementObjectSearcher windowsServicesSearcher = new ManagementObjectSearcher("root\\cimv2", "select * from Win32_Service"); ManagementObjectCollection objectCollection = windowsServicesSearcher.Get(); var services = objectCollection .Cast() .Select(mo => new { Name = mo.Properties["Name"].Value.ToString(), ProcessID = mo.Properties["ProcessId"].Value.ToString() }) .Where(s => s.ProcessID != "0") .ToList(); services .GroupBy(s => Int32.Parse(s.ProcessID), g => g.Name) .Where(g => Process.GetProcessById(g.Key).ProcessName.Contains("svchost")) .ToList() .ForEach(g => Console.WriteLine($"{g.Key}: \t {String.Join(",", g)}")); Способ сделать то же самое без кода и без сторонних утилит: В Task Manager в контекстном меню на списке процессов выбрать Go to service(s). Task Manager переключится на список сервисов, все сервисы внутри процесса будут выделены в списке:

Ответ 2



Зная PID, можно получить список окон данного процесса. Зная handle окна, ему можно отправлять сообщения, а значит узнать его класс, заголовок, все атрибуты, список дочерних окон и.т.д. (в примере как раз идет получение заголовка). В общем, с чужим окном через handle можно делать практически все то, что и с собственным. У интерактивных программ с GUI, очевидно, окон будет очень много. Как минимум одно из них является главным окном приложения, его можно идентифицировать по заголовку, атрибутам и набору дочерних окон. У процессов, подключенных к ServiceHost, окон, скорее всего, не будет вообще. Или будут какие-то служебные окна, но все они будут скрытые (проверяется это просто) и их набор будет довольно постоянным, так как пользователь не взаимодействует с GUI.

Завершение процесса

#android #процесс


Возможно ли завершить процесс через onBackPressed() ??

не получается так:

    h = new Handler() {
        public void handleMessage(android.os.Message msg) {
            new RequestREFRESH().execute(API_URL);
        }
    };


    System.out.println("Запускаю цикл обновления");
    Thread t = new Thread(new Runnable() {
        public void run() {

            for (int i = 1; i < 86400; i++)//86400-секунд в сутках
            {
                h.sendEmptyMessage(i);
                System.out.println("Запускаю функцию обновления");
                try {
                    System.out.println("Приостанавливаю поток на 5 секунд");
                    Thread.sleep(5000); //Приостанавливает поток на 5 секунд
                } catch (InterruptedException e) {
                    System.out.println("Ошибка задержки среды");
                    e.printStackTrace();
                }
            }

        }
    });
    t.start();

@Override
public void onBackPressed() {


    if (t != null) {
        Thread dummy = t;
        t = null;
        dummy.interrupt();
    }

}


переделал так:

    h = new Handler() {
        public void handleMessage(android.os.Message msg) {
            new RequestREFRESH().execute(API_URL);
        }
    };


    System.out.println("Запускаю цикл обновления");
    t = new Thread(new Runnable() {
        public void run() {

    try {
            for (int i = 1; i < 86400; i++)//86400-секунд в сутках
            {
                if (!t.isInterrupted()) {
                h.sendEmptyMessage(i);
                System.out.println("Запускаю функцию обновления");

                    try {
                       System.out.println("Приостанавливаю поток на 5 секунд");
                       Thread.sleep(5000); //Приостанавливает поток на 5 секунд
                    } catch (InterruptedException e) {
                        System.out.println("Ошибка задержки среды");
                        e.printStackTrace();
                    }

                } else {
                    throw new InterruptedException(); 
                }
            }
        } catch (InterruptedException e) {
            System.out.println("Thread is interrupted"); 
        }

        }
    });
    t.start();

@Override
public void onBackPressed() {


    if (t != null) {
        Thread dummy = t;
        t = null;
        dummy.interrupt();
    }

}


получил ошибку - FATAL EXCEPTION: Thread-83
    


Ответы

Ответ 1



У Вас после interrupt() должен сработать блок catch (правда не сразу, конечно). Добавьте в него break, чтобы выйти из цикла и корректно завершить работу потока. Также корректно было бы добавить в условие цикла !isInterrupted(), помимо условия i < 86400. ОБНОВЛЕНО Переделали Вы странно. Достаточно было в блок catch после вывода e.printStackTrace() вписать команду break, а также изменить условие в цикле на i < 86400 && !isInterrupted(). Еще один try-catch и выброс своего exception бессмысленны.

пятница, 10 января 2020 г.

Принудительное завершение дочернего процесса из родителя в fork() в си

#c #процесс


Возможно ли завершить дочерний процесс не дожидаясь его окончания с помощью функции
wait()? Например, как завершить вот такой дочерний процесс:

pid_t pid;
switch(pid=fork()) {
case 0:
  for(;;){}
default:
  //здесь код, который завершает дочерний процесс
  return 0;


P.S. Если вы знаете какой-то адекватный, не сильно мудреный материал по fork(), где
можно почерпнуть теоретические знания, то направьте меня, пжл.
    


Ответы

Ответ 1



Жестокий метод: kill(pid, SIGKILL); Или более мягко: kill(pid, SIGTERM); В первом случае дочерний процесс будет просто убит, во втором получит сигнал, который может обработать. Но SIGKILL убъёт процесс гарантированно, а в случае SIGTERM процесс может отказаться заканчивать работу. В приведённом коде, поскольку процесс, похоже, не содержит обработчиков сигналов, можно использовать любой метод, поскольку, как верно указал на мою ошибку @avp, SIGTERM при отсутствии обработчика также убьёт процесс.

четверг, 9 января 2020 г.

Путь к файлу процесса c#

#c_sharp #процесс


Получаю список процессов 

 System.Diagnostics.Process[] procList = System.Diagnostics.Process.GetProcesses();


Как узнать папку, где находится этот процесс ? 
Пытался так 

procList[0].MainModule.FileName  - возвращает null

procList[0].StartInfo.FileName  - возвращает пустую строку

Есть еще способы ? 
    


Ответы

Ответ 1



Если Вам нужно получить путь программы откуда запускаете свой файл: using System.Linq; using System.Diagnostics; try { foreach (var proc in Process.GetProcesses().Where(p => !string.IsNullOrEmpty(p.MainWindowTitle)).ToList()) { Console.WriteLine(proc.MainModule.FileName); } } catch { /*Тут ловим исключения*/ } Так же без использования Linq Console.WriteLine(Process.GetCurrentProcess().MainModule.FileName); Имя запускаемого файла можно узнать так: Console.WriteLine(Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName)); Чтобы перечислить все папки через процессы можно воспользоваться таким способом: foreach (Process instance in Process.GetProcesses()) { try { Console.WriteLine(instance.ProcessName); Console.WriteLine(instance.MainModule.FileName); } catch (System.ComponentModel.Win32Exception w32ex) { Console.WriteLine(w32ex.Message); } catch (Exception ex) { Console.WriteLine(ex.Message); } } Если же Вы хотите получить все папки процессов можно воспользоваться через WMI using (var mCollection = new ManagementClass("Win32_Process").GetInstances()) { foreach (ManagementObject process in mCollection) { Console.WriteLine((string)process["ExecutablePath"]); //Console.WriteLine(FileVersionInfo.GetVersionInfo((string)process["ExecutablePath"]).FileDescription); } }

понедельник, 6 января 2020 г.

Как отследить время работы программы/процесса

#c_sharp #windows #процесс


Как отследить работу не моей программы, а программы на OC windows, или сколько работает
процесс/служба? 
    


Ответы

Ответ 1



Находишь нужный тебе процесс и у него читаешь свойство Process.StartTime. Зная время старта процесса и текущее время(DateTime.Now) вычитаешь одно из другого и получаешь время сколько процесс работал. Например, так: var minutes=(DateTime.Now - Process.GetProcessesByName("Word").First().StartTime).TotalMinutes;

суббота, 4 января 2020 г.

Дожидаться окончания не-дочернего процесса

#linux #bash #процесс


Есть ли в bash встроенная функция для ожидания завершения процесса вроде wait(pid),
но для не-дочернего процесса?

Если нет, то каким образом можно дожидатся окончания процесса?

Интересует не механический способ проверки циклом, а что-то вроде прерываний.
    


Ответы

Ответ 1



Я предполагаю, что автора интересует не произвольный процесс, а некий демон. Если этот демон "честно" создаёт pid-файл, то можно попробовать навесить inotify на удаление этого файла. Тогда, при завершении процесса демона, он будет удалять свой pid-файл, а ОС пошлёт Вам соответствующий сигнал. Но, как очевидно, при аварийном падении демона этот фокус не пройдёт...

Ответ 2



Вам нужен цикл ожидания, очевидно же :) while [ $(pgrep $1)>'0' ] do sleep 5 done

Ответ 3



Как вариант можно предложить скрипт, который в цикле отслеживает заданный PID и посылает вызывающему скрипту (его PID передается вторым аргументом) сигнал. Например: #!/bin/bash if [ $# -ne 2 ]; then echo usage: wdog.sh PID-watch PID-signal exit 1 fi while [ -d /proc/$1 -a -d /proc/$2 ] do sleep 1 done [ -d /proc/$2 ] && kill -1 $2 И пример вызывающего скрипта: #!/bin/bash I=0 trap "echo catch Sighup;I=1" SIGHUP ./wdog.sh $1 $$ & echo read loop while read a do if [ $I == 1 ]; then echo end loop I=$I break fi done Следует учесть, что сигнал тут будет обработан в read (поскольку это встроенная команда), однако выход по прерыванию не происходит. Если же скрипт вызвал какую-либо внешнюю команду (grep, cat ...), то обработка сигнала произойдет после ее завершения. Если воспользоваться ответом @alexanderbarakin (и strace у вас работает (по крайней мере мне в Ubuntu пришлось от рута выполнить echo 0 >/proc/sys/kernel/yama/ptrace_scope, чтобы она заработала для отслеживания произвольного процесса с тем же UID)), то цикл ожидания в скрипте wdog.sh можно заменить на strace -qe '' -p $1 2>/dev/null

Ответ 4



в ответах на вопрос WAIT for “any process” to finish приведены некоторые соображения по этому поводу: какого-либо встроенного (или даже просто заведомо работоспособного) средства, конечно, нет. у меня получилось воспользоваться программой strace, как предложили в одном из ответов. манипуляций с псевдо-файловой системой /proc при этом не потребовалось: $ strace -qe '' -p идентификатор.процесса понятно, что «следить» за процессами, запущенными другими пользователями, не получится, пока не запустите strace от имени пользователя root.

Ответ 5



вот из этого мануала я узнал следующее: Для досрочного завершения потока можно воспользоваться функцией pthread_cancel. Единственным аргументом этой функции является идентификатор потока. Функция pthread_cancel возвращает 0 в случае успеха и ненулевое значение(код ошибки) в случае ошибки. Функция pthread_setcancelstate определяет, будет ли поток реагировать на обращение к нему с помощью pthread_cancel. То есть получается надо отменить удаление функцией pthread_cancel с помощью pthread_setcancelstate и анализировать какие коды возвращает pthread_cancel, и скорей всего она будет возвращать какой то код ошибки типа поток не найден если его нет и при всем при этом она этот поток не сможет завершить.

четверг, 2 января 2020 г.

Как убить неубиваемый процесс в Windows 7?

#windows_7 #процесс


Как убить неубиваемый процесс? "Завершить процесс в ДЗ" - не идет;
стороннее ПО AnvirTaskManager - не помогает, командная строка через "taskkill /IM
*.exe /F" также не спасает. Ума не приложу
ОС Win7
    


Ответы

Ответ 1



Если отбросить автоматически перезапускающиеся процессы, то да, действительно, в Windows иногда встречаются "неубиваемые" процессы. Он делятся на две группы. К первой относятся защищённые процессы, например, процессы антивируса, для "убийства" которых у пользователя не хватит прав и "зависшие", которые по каким-то причинам система "убить" не может. В моей практике встречались процессы из второй группы. Один раз так у меня завис отладчик GDB. Для снятия таких зависших неубиваемых процессов можно использовать, например, Process Explorer Марка Руссиновича. Позволяет снять почти любой процесс. Но иногда не помогает. Тогда можно попробовать программу Process Hacker. В её арсенале целый набор методов для снятия процессов. Если не справился Process Explorer, часто помогает Process Hacker. Правой кнопкой мыши на требуемом процессе -> Miscellaneous -> Terminator. Также, если завис процесс какой-либо IDE в момент отладки, может помочь правой по отлаживаемому процессу Miscellaneous -> Detach from Debugger. Однако, иногда встречается такая гадость, что её невозможно снять никаким методом. Почему это происходит, мне неизвестно. Но пару раз встречалось. И не всегда при этом машина способна нормально уйти в перезагрузку, иной раз этот зависший процесс не даёт этого сделать. И тогда помогает только кнопка Reset.

Ответ 2



А если попробовать программой unlocker ?

воскресенье, 29 декабря 2019 г.

c# Как обнаружить вторжение в память своей программы

#c_sharp #процесс #защита #виртуальная_память


Существуют различные программы по захвату текста с форм (например в ЯП Autoit, есть
функция ControlGetText, которая считываем с контролера текст), есть программы, которые
вообще позволяют влезать в память процесса, такие как Cheat Engine (например). 

Собственно вопрос. Есть ли способ обнаружения "вторжения" в память своей программы?
Как это можно реализовать? В какую сторону копать? 
    


Ответы

Ответ 1



Нашел интересный ответ: Ничего не мешает злоумышленнику заморозить ваш процесс, сделать все необходимые действия и убить процесс => процесс не узнает ничего о том, что кто-то его читал. Можно так сделать дамп памяти и опять же процесс не будет знать, что кто-то читал его память. Существуют дебаггеры, которые позволяют перелопатить ваш процесс по косточкам. Как вы указали в своем вопросе, то самые банальный пример- это взлом компьютерных игр. Если бы разработчики имели универсальное решение, то все бы читеры давно вымерли, а они все плодятся и плодятся => нельзя защитить память своего приложение. Разработчики вынуждены использовать анти-читы и ловить подозрительные активности игроков. Закрытость платформы, где юзер имеет ограниченные возможности, может обеспечить защиту от взлома процесса. Например, игровые консоли. Еще один выход- это хранить важную информацию на сервере, куда злоумышленник имеет меньшую вероятность попасть и время от времени выполнять верификацию клиента. Так, обычно, делается в ММОРПГ. Подводя итог: Вы больше всего зависите от среды в которой работает ваше приложение. Если она имеет API для обнаружения, то используйте его, в противном случае у вас нету никаких возможностей, так как памятью рулит ОС, а не вы. Например, у Windows есть DEP, который мониторит память и предотвращает запуск вредоносного кода из стороннего процесса.

понедельник, 23 декабря 2019 г.

Недопонимание с Linux на примере демона.

#linux #c #процесс #демон


Чтобы создать демона (по крайней мере в Linux), то нужно предпринять ряд событий,
которые я сейчас опишу. В конце вопросы, если кто-то разбирается, то просьба овтетить,
буду признателен.

1) Нужно вызвать функцию fork() для создания дочернего процесса и завершить родительский
процесс. Это делается для того, чтобы наш дочерний процесс запутился в фоновом режиме
(если не прав, то поправляйте) 

if( (pid = fork()) < 0)
         return -1;
else if(pid)
         exit(0);


2) Затем мы вызываем функцию setsid(), которая создает новый сеанс. К тому же, вызывающий
процесс становится ведущим в группе, ведущим процессом нового сеанса и не имеет контролирующего
терминала.

if(setsid() < 0) 
        return -1;


В книге "Разработка сетевых приложений" Стивенс У.Р, откуда я и беру этот пример,
автор вызывает еще один раз функцию fork(), для того, чтобы гарантировать, что демон
не сможет автоматически получить управляющий терминал, когда будет открывать устройство
терминала. Заметьте, что при завершении родительского процесса (в нашем случае первого
дочернего процесса), посылается всем процессам в сеансе (в том числе и нашему второму
дочернему процессу) сигнал SIGHUP (when someone kills the terminal, without killing
app running inside of termiтal window, OS sends the signal to the program), который
нам нужно игнорировать. 

3) Производим смену текущего каталога командой chdir("/");

4) Закрываем дескрипторы файлов. Автор делает это таким образом

for(i = 0; i < 64; i++) 
        close(i);


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

Собственно говоря, мои вопросы:

1) Вопрос может показаться глупым, но я не совсем понимаю, что означает управляющий
терминал. Это что-то вроде терминала из под root? Объясните, пожалуйста, что это и
что он делает.

2) Зачем нужно менять текущий каталог? В книге об этом сказано мало и мне не совсем
понятно

3) За что отвечают дескрипторы, которые мы закрываем? И нужно ли их вообще закрывать? 
    


Ответы

Ответ 1



Вопрос может показаться глупым, но я не совсем понимаю, что означает управляющий терминал. Это что-то вроде терминала из под root? Объясните, пожалуйста, что это и что он делает. Если кратко, то это терминал связанный с текущей консольным сеансом (session). Указан в частности в столбце TTY ps'а. По факту он эквивалентен одному из устройств /dev/tty* для «настоящей» консоли или /dev/pts* для псевдотерминалов (unix98). Также есть специальное устройство /dev/tty, ссылающееся на управляющий терминал (controlling terminal) текущего процесса. Основное назначение этой абстракции — переключение между группами процессов — только одна из которых может быть на переднем плане (foreground), а остальные в фоне (background). Также УТ (находясь в каноническом режиме) отвечает за посылку сигналов процессам находящимся на переднем плане при появлении на входе специальных символов (например ^C или ^Z) . Кроме того с помощью УТ программы могут запрашивать непосредственно у пользователя какие-то данные, например пароль, когда ввод/вывод перенаправлен, так в частности поступают ssh или sudo. Вообще говоря, в UNIX управление заданиями, да и всей подсистемы связанной с терминалами, — довольно запутанная вещь со множеством мелких и крупных кочек, большинство из которых навеяно историей и необходимостью сделать всё гибко, но в то же время чисто, так что описание назначения и деталей УТ, а также таких абстракций, как «группа процессов», «сессия», «лидер сессии» итд, заслуживают отдельной главы в книге или хотя бы статьи. 2) Зачем нужно менять текущий каталог? В книге об этом сказано мало и мне не совсем понятно В принципе это не обязательно, но является хорошей практикой освобождать неиспользуемые ресурсы. Например, если это не сделать, то нельзя будет отмонтировать ФС с каталогом откуда пользователь запустил демона. 3) За что отвечают дескрипторы, которые мы закрываем? И нужно ли их вообще закрывать? То же что и предыдущее, не обязательно, но обычно является хорошей практикой. Первые три — это стандартные потоки ввода/вывода/ошибок, а остальные — другие дескрипторы, которые могут быть открыты — различные сокеты, файлы итп. К сожалению, в POSIX нет простого и переносимого способа, который позволяет просто «закрыть все открытые дескрипторы» или хотя бы «запросить все открытые д.», поэтому обычной практикой является перебирать их все подряд, от нулевого до последнего и закрывать. Да, более переносимым вариантом, не полагающийся на магическую константу «64», будет: for(int fd=0, maxfd=sysconf(_SC_OPEN_MAX); fd

понедельник, 16 декабря 2019 г.

Реализация алгоритма планирования SRR для Q = 2

#алгоритм #процесс #планирование


Объясните пожалуйста, как работает алгоритм диспетчеризации SRR для Q = 2. 
На рисунке показано, что при Q = 1, приоритеты процессов пересчитываются каждый квант
времени. 



Если Q=2, тогда приоритеты процессов будут изменяться по тому же принципу, только
через 2 кванта времени? То есть, через каждые 2 кванта приоритеты будут увеличиваться
на 2(для новых процессов) или на 1(которые уже использовали ЦП). Или же процесс просто
будет занимать ЦП 2 кванта времени, а его приоритет все равно будет увеличиваться каждый
квант? Не пойму точно, как работает алгоритм планирования для разных значений количества
квантов Q. Прошу пояснить. Заранее благодарен за помощь. 
    


Ответы

Ответ 1



SRR отличается от обычного RR (аббревиатуры для Selfish Round Robin и Round Robin) изначальным приоритетом для новых процессов. Например, в случае обычного RR приоритет для всех процессов одинаковый, потому все процессы получают равное количество времени. В случае SRR ситуация несколько иная: более старые процессы имеют больший приоритет, потому получают больше процессорного времени. На графике видно что задача A заняла два слота времени, хотя на время второго слота приходится новая задача B. Детали роста приоритета у старых и новых задач вы упоминаете в вопросе, останавливаться на них не буду. Вопрос насчёт Q относится не сколько к SRR, сколько к RR вообще. Q (от quantum) - часть времени процессора которая даётся задаче на работу до вытеснения другой задачей. Если Q=2, то задаче даётся две части времени. Хватило - молодец, а не хватило - тоже не проблема, просто жди своей очереди. Как вы заметили, в случае SRR на выделение времени влияет также приоритет процесса, который, в свою очередь, зависит от возраста и типа процесса (accepted или нет).