Что такое set perm recursive в программирование
FAQ по созданию патча update.zip для прошивки через рекавери
Редактирование Updater-script. Информация, решения, команды, подпись патчей.
Инструкция по установке системных и пользовательских приложений с помощью recovery
Редактирование установленной прошивки и удаление системных приложений
(ключевые слова)
Напоминаю, тут не стол заказов. Автору в qms НЕ писать. Посты с просьбой собрать zip для «хххх» Recovery оффтоп
Сообщения, не относящиеся к теме обсуждения (оффтоп), удаляются без предупреждения
- Добавление нескольких пользовательских/системных приложений «за один клик» (одним патчем).
- Добавление/удаление системных приложений без root прав и вспомогательных программ.
- Изменение прошивки (замена файлов, украшательства и т.д.).
- Обновление программы или прошивки.
- Переразметка памяти (обсуждения в другой теме)
- Получение root прав SuperUser, SuperSU, Magisk
- Установленный на телефоне кастомный рекавери (CWM/TWRP)
(редактор с сохранением Unix формата) - Zip_signer (подписчик архивов)
- Файл-заготовка sample.zip (либо update-binary для ручной сборки)
Zip_signer.rar ( 13.28 КБ )
sample-patch.rar ( 4.77 МБ )
update-binary.rar ( 113.25 КБ ) - Дополнительные версии бинарника. binary_all.rar ( 649.36 КБ )
- Бинарники (архив/исходники)
Исходники бинарника, основная ссылка:
https://android.google…ootable/recovery/+refs
выбираем к примеру «android-9.0.0_r18» , потом ищем папку «updater», в папке «updater» исходники бинарника
К примеру https://android.google…droid-9.0.0_r18/updater — можно глянуть все команды которые может выполнить бинари в андроид 9.0.0 (в файле install.cpp, в самом низу)
- Собрать свой update.zip (из заготовки sample.zip)
- Подписать update.zip утилитой Zip_signer(Не обязательно!)
- Закинуть на флэшку и установить в аппарат через ClockWorkMod Recovery
- Разархивировать архив sample.zip
- Удалить файлы подписи META-INF/CERT.RSA, CERT.SF, MANIFEST.MF (т.к. 2м шагом мы их будем создавать для своей сборки)
- Поместить в папку /data/app свое пользовательское приложение (xxxxx.apk)
- При необходимости отредактировать файл updater-script (подробнее позже)
- Заархивировать всё (META-INF и data) ZIP’ом без сжатия
- Переименовать Ваш отредактированный (т.е. уже с приложением внутри) sample.zip в update.zip
- Поместить его в папку с программой Zip_signer
- Запустить файл zip_signer.bat
- Дождаться, пока процесс будет завершен
- В папке появится файл update-finished.zip — это и есть подписанный файл
- Переименовать update-finished.zip по своему усмотрению (согласно логике патча)
- Перекинуть (переименованный) update-finished.zip на флэшку и установить его в аппарат через TWRP или CWM (install zip from sdcard -> chooze zip from internal sdcard -> Yes, install sample.zip)
- Перезагрузить аппарат
- Скачиваем signapk.zip и разархивируем в папку <папка-signapk>
- Назначаем права для всего содержимого — «rwxrwxrwx» (chmod -R 777
Внимание! Патчи создаются только для мод.рекавери и результативно работают только в них. В стоковых рекавери (на аппаратах «из коробки») патчи не работают.
- папка META-INF
- папка источник установки приложений (system, data, sdcard, cache, sd-ext)
Обязательные файлы: - META-INF/com/google/android/update-binary — системное средство запуска данного патча, также создает временную рабочую папку tmp
- META-INF/com/google/android/updater-script — выполняемый скрипт по которому и происходят операции копирования и т.д.
Разберем sample.zip
Патч добавляет пользовательское приложение MyPiano в Data.
• package_extract_dir
Синтаксис: package_extract_dir(«<src-dir>», «<dst-dir>»);
Копирует содержимое <src-dir> в <dst-dir>. Файлы в <dst-dir> имеющиеся в <src-dir> перезаписываются.
Пример: package_extract_dir(«system», «/system»); Скопирует файлы из папки update.zip/system в /system
• package_extract_file
Синтаксис: package_extract_file(«<src-file>», «<dst-file>»);
Копирует файл <src-file> в <dst-file>. Если файл <dst-file> существует, то он перезаписывается.
Пример: package_extract_file(«test.sh», «/tmp/test.sh»); Скопирует файл test.sh из update.zip в /tmp/test.sh
• format
Синтаксис: format(«MTD», «<root>»);
Форматирует раздел <root>(см. приложение).
Пример: format(«MTD», «system»); Полностью отформатирует /system . Примечание: форматирование удаляет данные необратимо.
Пример 2: format(«ext4», «EMMC», «/dev/block/mtdblock5», «0», «/system»);
Определение номера блока под спойлером «инфо и материалы».
• delete
Синтаксис: delete(«<file1>»[, «file2», . «fileN»]);
Удаляет файл(ы)
Пример: delete(«/system/app/Calculator.apk»); Удалит Calculator.apk из папки system/app.
• delete_recursive
Синтаксис: delete_recursive(«<dir1>»[, «dir2», . «dirN»]);
Рекурсивно удаляет папку(и) со всем содержимым
Пример: delete_recursive(«/data/dalvik-cache»); Удалит папку /data/dalvik-cache со всем содержимым.
• run_program
Синтаксис: run_program(«<filetorun>»[, «<opt1>», «<opt2>», «<opt3>»]);
Запускает программу(скрипт) <filetorun>.
Пример: run_program(«/tmp/install_busybox.sh»); Запустит скрипт /tmp/install_busybox.sh.
• set_perm
Синтаксис: set_perm(<uid>, <gid>, <mode>, «<pathtofile>»[, . «pathtofileN»]);
Устанавливает владельца, группу и разрешения для файла или папки, как ‘chmod’, ‘chown’, и ‘chgrp’ всё в одном
Пример: set_perm(0, 2000, 0550, «/system/etc/init.goldfish.sh»); Установит владельца, группу и разрешения для файла /system/etc/init.goldfish.sh
• set_perm_recursive
Синтаксис: set_perm_recursive(<uid>, <gid>, <dir-mode>, <file-mode>, «<path>»[, . «<pathN>»])
Рекурсивно устанавливает владельца, группу и разрешения для содержимого папки. <dir-mode> — для папок, <file-mode> — для файлов.
Пример: set_perm_recursive(0, 0, 0755, 0644, «/system/app»); Установит права для содержимого /system/app, для папок — 0755, для файлов — 0644.
• show_progress
Синтаксис: show_progress(<fraction>, <duration>);
Продвижение прогрессбара на долю <fraction> за <duration> секунд. <duration> может быть нулевым для продвижения его по командe set_progress, а не по времени.
Пример: show_progress(0.100000, 1); Увеличит прогресс на 0.1 часть за 1 секунду
• set_progress
Синтаксис: set_progress(<fraction>);
Устанавливает положение прогрессбара на долю <fraction>, для самого последнего вызова команды show_progress.
Пример: set_progress(0.500000);
• symlink
Синтаксис: symlink(«<link-target>», «<link-path1″[, «<link-path2>», «<link-path3>»]);
Создает символическую ссылку (как ‘ln-s’). <link-path> пишется в формате root:path, а <link-target> в формате целевой файловой системы (и может быть относительным). Википедия Symlink.
Пример: symlink(«/data/app_s», «/system/app»); Создаст символическую ссылку на папку /data/app_s для папки /system/app
• mount
Синтаксис: mount(«<kind>», «<what>», «<path>»);
Монтирует <what> в путь <path>. <what> должно быть название раздела, если <kind> это «MTD», или блок памяти если <kind> это «vfat»
Пример: mount(«MTD», «userdata», «/data»);
• unmount
Синтаксис: unmount(«<path>»);
Отключает <path>.
Пример: unmount(«/data»);
• ui_print
Синтаксис: ui_print(«<message>»);
Выводит на экран сообщение <message>
Пример: ui_print(«Formatting SYSTEM. «);
• sleep
Синтаксис: sleep(<time>);
Пауза процесса на <time> секунд
Пример: sleep(5); — пауза 5 секунд, после чего код скрипта выполняется дальше.
• set_metadata / set_metadata_recursive
Синтаксис: set_metadata (. );
Устанавливает владельца, группу и разрешения (новая команда взамен set_perm для andriod 4.4.*)
Примеры: Android update-script (Пост #32151495)
Создание патча update.zip для прошивки через рекавери (Пост kory-vadim #81945464)
• set_metadata / set_metadata_recursive
Синтаксис:
set_metadata(«имя файла», «ключ1», «значение1», «ключ2», «значение2», . )
set_metadata_recursive(«имя директории», «ключ1», «значение1», «ключ2», «значение2», . )
Ключи:
* uid
* gid
* mode (set_perm_extd only)
* fmode (set_perm_extd_recursive only)
* dmode (set_perm_extd_recursive only)
* selabel
* capabilities
первые три (uid, gid, mode) это тоже самое что и в chmod, заполняется «uid», 0, «gid», 1000, «mode», 06754.
для установки прошивки хватает трех ключей «uid», 0, «gid», 1000, «mode», 06754.
Пример: set_metadata(«/system/xbin/shelld», «uid», 0, «gid», 1000, «mode», 06754, «capabilities», 0x0, «selabel», «u:object_r:system_file:s0»);
set_metadata_recursive(«/system/xbin», «uid», 0, «gid», 2000, «dmode», 0755, «fmode», 0755, «capabilities», «0x0», «selabel», «u:object_r:system_file:s0»);
• команды для Nexus’ов
block_image_update(«/dev/block/platform/msm_sdcc.1/by-name/system», package_extract_file(«system.transfer.list»), «system.new.dat», «system.patch.dat»);
Синтаксис: block_image_update(«Путь к блоку раздела», package_extract_file(«список информации для патча (?) «), «образ», «патч образа»);
я так понимаю, что так прошивается сильно сжатая прошивка (образ системы).
Еще ifelse
Пример: ifelse(is_mounted(«/system»), unmount(«/system»)); — если раздел сустем смонтирован дается команда на его размонтирование, если размонтиовать то нечего не происходит.
• Информация по атрибутам set_metadata и подобным командам на Android 4.4+
Android update-script (Пост blackeangel #50803606)
Описание откуда берутся «u:object_r:uncrypt_exec:s0» и подобные атрибуты. . .
• Пример скрипта который может удалять\перемещать\бекапить файлы и вести лог действий
Android Script Creator (Пост Octanium #51085030)
• Временный Busybox
Используется при отсутствии busybox, либо чтоб не привязываться к его расположению в системе.
Что такое set perm recursive в программирование

package_extract_dir
package_extract_file
format
delete
delete_recursive
run_program
set_perm
set_perm_recursive
show_progress
set_progress
symlink
mount
unmount
ui_print
Python recursion permutations
Im having trouble trying to make a permutation code with recursion. This is suppose to return a list back to the use with all the posible position for each letter. so for the word cat it is suppose to return [‘cat’,’act’,atc,’cta’,’tca’,’tac’] . so far i have this
There are steps there but im not sure how to use them
![]()
10 Answers 10
You want to do recursion, so you first have to find out how the recursion would work. In this case it is the following:
And as a final condition:
So the recursion splits up the list in sublists with one element extracted each time. Then this element is added to the front of each of the permutations of the sublist.
So in pseudo-code:
Recursively, think about the base case and build from that intuition.
1) What happens when there’s only one character ‘c’? There’s only one permutation of that element, and so we return a list containing only that element.
2) How can we generate the next permutation given the last one? Adding an additional letter ‘a’ at all possible positions in the previous permutation ‘c’ gives us ‘ca’, ‘ac’.
3) We can continue building larger and larger permutations by adding an additional character at all possible positions in each earlier permutation.
The following code returns a list of one character if the string has one character or less. Otherwise, for all permutations not including the last character in the string s[-1], we generate a new string for each position where we could include that character and append the new string to our current list of permutations.
updater-script как правильно составить
Необходимо создать updater-script для вашей кастомной прошивки или мода? Не знаете какие команды писать и что они означают? На все эти ответы можно узнать из данной статьи.
Как должен выглядеть ZIP -обновление (структура)

В корне архива-обновления «должны» находится такие файлы и папки:
- Папка META-INF — обязательно;
- system или data или cache или другие, в зависимости от того, для чего готовилось обновление (не обязательно, так как возможно прошиваете модем или ядро);
- boot.img или recovery.img или zImage (не обязательно, так как возможно обновляете файл в system или data).
Режим сжатия архива должен быть «нормальный» или «обычный» более сильное сжатие Android не поддерживает.
Папка META-INF состоит:

- Папка com
- Файлы подписи обновления
Папка com должна содержать в себе такие файлы и папки:
- Папку android
Папка google должна содержать папку android в которой должны быть файлы
1. updater-script — текстовый файл с набором инструкций для обновления;
2. update-binary — бинарный файл, необходимый для установки обновления.

Инструменты редактирования update-script
Для редактирования updater-script вам понадобится программа NotePad ++
важное условие при работе это кодировка, она должна быть UNIX
![]()
Команды updater-script
- assert -задается для каких моделей создано обновление;
- mount — монтирование (присоединение) разделов;
- umount — отсоединить раздел;
- package_extract_dir — копирует выбраню папку и заменяет собой аналогичную вместе с файлами;
- package_extract_file — копирует выбранный файл и заменяет собой аналогичный;
- format — форматирует прописанный раздел;
- delete — удаляет файл;
- delete_recursive — рекурсивное удаление, необходимо для удаления папок и их содержимого;
- run_program — запускает программу;
- set_perm — задает права для файла;
- set_perm_recursive — задает права для папки;
- symlink — создает жесткую ссылку — «симлинк» (ярлык для запуска);
- ui_print — вывод сообщения на экран.
Внимание! Программа Android +1 Updater Script
Вашему внимание проект сайта Android +1 — Android +1 Updater Script позволит правильно и очень быстро составить правильный скрипт, даже для пользователей с маленьким опытом!
Как узнать как задать правильные symlink в updater-script
Довольно популярный вопрос о том как узнать какие необходимо создать symlink в updater-script? Все очень просто для этого вам нужно либо компьютер с ADB или установленный терминал на Android. Перейдите в папки:
- bin
- fonts
- lib
- xbin
В каждой из этих папок наберите команду ls -l и вы получите список файлов и symlink.
Узнать список всех папок в System
Для того того чтобы узнать все папки которые есть в разделе /system , понадобиться набрать linux команду:
su
du -a system
После чего вам выдаст весь список папок в разделе.
Узнать все права, uid, gid и список файлов и папок
Для того чтобы узнать все права, uid, gid и список файлов и папок нужно задать следующую команду linux:
ls -alnR /system
Теперь перейдем как это выглядит в живую на примере…
Пример updater-script
(данный пример update-script для модели i9100 прошивка CyanogenMod 10.2)
для каких моделей:
[spoiler title=’assert’ style=’default’ collapse_link=’true’]
assert(getprop(«ro.product.device») == «galaxys2» || getprop(«ro.build.product») == «galaxys2» ||
getprop(«ro.product.device») == «i9100» || getprop(«ro.build.product») == «i9100» ||
getprop(«ro.product.device») == «GT-I9100» || getprop(«ro.build.product») == «GT-I9100» ||
getprop(«ro.product.device») == «GT-I9100M» || getprop(«ro.build.product») == «GT-I9100M» ||
getprop(«ro.product.device») == «GT-I9100P» || getprop(«ro.build.product») == «GT-I9100P» ||
getprop(«ro.product.device») == «GT-I9100T» || getprop(«ro.build.product») == «GT-I9100T»);
монтирование раздела
копирование файла
[spoiler title=’package_extract_file’ style=’default’ collapse_link=’true’]
package_extract_file(«system/bin/backuptool.sh», «/tmp/backuptool.sh»);
package_extract_file(«system/bin/backuptool.functions», «/tmp/backuptool.functions»);
задание прав для файла
[spoiler title=’set_perm’ style=’default’ collapse_link=’true’]
set_perm(0, 0, 0777, «/tmp/backuptool.sh»);
set_perm(0, 0, 0644, «/tmp/backuptool.functions»);
запуск программы
[spoiler title=’run_program’ style=’default’ collapse_link=’true’]
run_program(«/tmp/backuptool.sh», «backup»);
отсоединить раздел
[spoiler title=’unmount’ collapse_link=’true’]
unmount(«/system»);
прогрессбар
[spoiler title=’show_progress’ collapse_link=’true’]
show_progress(0.500000, 0);
форматирование заданного раздела
подсоединение раздела
копирование папки в выбранный раздел
[spoiler title=package_extract_dir’ collapse_link=’true’]
package_extract_dir(«recovery», «/system»);
package_extract_dir(«system», «/system»);
создание симилнка
рекурсивное выставление прав папкам
[spoiler title=’set_perm_recursive’ collapse_link=’true’]
set_perm_recursive(0, 0, 0755, 0644, «/system»);
set_perm_recursive(0, 0, 0755, 0755, «/system/addon.d»);
set_perm_recursive(0, 2000, 0755, 0755, «/system/bin»);
рекурсивное выставление прав файлам
[spoiler title=’set_perm’ collapse_link=’true’]
set_perm(0, 3003, 02750, «/system/bin/netcfg»);
set_perm(0, 0, 0755, «/system/bin/ping»);
set_perm(0, 2000, 0750, «/system/bin/run-as»);
set_perm(1014, 2000, 0550, «/system/etc/dhcpcd/dhcpcd-run-hooks»);
set_perm_recursive(0, 2000, 0755, 0755, «/system/etc/init.d»);
set_perm(0, 0, 0755, «/system/etc/init.d»);
set_perm(0, 2000, 0550, «/system/etc/init.goldfish.sh»);
set_perm_recursive(0, 0, 0755, 0555, «/system/etc/ppp»);
set_perm(0, 2000, 0755, «/system/vendor»);
set_perm_recursive(0, 2000, 0755, 0644, «/system/vendor/etc»);
set_perm(0, 0, 0644, «/system/vendor/etc/audio_effects.conf»);
set_perm(0, 2000, 0755, «/system/vendor/firmware»);
set_perm(0, 2000, 0755, «/system/vendor/lib»);
set_perm_recursive(0, 2000, 0755, 0644, «/system/vendor/lib/drm»);
set_perm(0, 0, 0644, «/system/vendor/lib/drm/libdrmwvmplugin.so»);
set_perm_recursive(0, 2000, 0755, 0755, «/system/xbin»);
set_perm(0, 0, 06755, «/system/xbin/librank»);
set_perm(0, 0, 06755, «/system/xbin/procmem»);
set_perm(0, 0, 06755, «/system/xbin/procrank»);
set_perm(0, 0, 06755, «/system/xbin/su»);
прогреccбар
[spoiler title=’show_progress’ collapse_link=’true’]
show_progress(0.200000, 0);
show_progress(0.200000, 10);
копирование файла
[spoiler title=’package_extract_file’ collapse_link=’true’]
package_extract_file(«system/bin/backuptool.sh», «/tmp/backuptool.sh»);
package_extract_file(«system/bin/backuptool.functions», «/tmp/backuptool.functions»);
задание прав для файла
[spoiler title=’set_perm’ collapse_link=’true’]
set_perm(0, 0, 0777, «/tmp/backuptool.sh»);
set_perm(0, 0, 0644, «/tmp/backuptool.functions»);
запуск программы
[spoiler title=’run_program’ collapse_link=’true’]
run_program(«/tmp/backuptool.sh», «restore»);
удаление файла
[spoiler title=’delete’ collapse_link=’true’]
delete(«/system/bin/backuptool.sh»);
delete(«/system/bin/backuptool.functions»);
прогрессбар
[spoiler title=’show_progress’ collapse_link=’true’]
show_progress(0.200000, 10);
установка ядра
[spoiler title=’write_raw_image’ collapse_link=’true’]
assert(package_extract_file(«boot.img», «/tmp/boot.img»),
write_raw_image(«/tmp/boot.img», «/dev/block/mmcblk0p5»),
delete(«/tmp/boot.img»));
прогрессбар
[spoiler title=’show_progress’ collapse_link=’true’]
show_progress(0.100000, 0);
отсоединение раздела
Бонус: Полезные команды в конце скрипта
Выполнить wipe Dalvik cache, для во избежания сбоев в системе (ставить до umount в конце):
delete_recursive(«/data/dalvik-cache»)
автоматическая перезагрузка (ставить после umount в конце)
run_program(«/sbin/reboot»);
Многопоточное программирование в Linux
В линуксе ( точнее в pthreads) используется одноуровневая система потоков, так называемая N-to-N ( или 1-1 ) реализация, которая мултеплексирует созданные пользователем потоки в такое же количество выполняемых потоков ядра. Однако, на самом деле, потоки в линуксе являются обыкновенными процессами, имеющими свой уникальный pid_t, стек, но разделяющие между собой определенные составляющие контекста процесса — его память , таблицу файловых дескрипторов, таблицу обработчиков сигналов. Такого рода процессы именуются «облегченными» (LWP — Light Weight Processes), и в линуксе для их создания ( как и для создания обыкновенных процессов ) используется системный вызов __clone(2).
Сигнатура этого вызова такова: int __clone(int (*fn) (void *arg), void *child_stack, int flags, void *arg)
Младший байт праметра flags содержит номер сигнала, посылаемого родительскому прцессу, когда завершается соданный им потомок. Параметр также может быть установлен с помощью операции побитового или ( | ) со следующими костантами,чтобы указать что именно разделятся между потомком и родителем:
Если CLONE_VM установлен, родитель и потомок выполняются в одном адресном пространтсве. В частности, запись в память выполненная в потомке или родителе, также видна в другом процессе. Общей является и работа с отображаемой памятью, выполняемая с помощью системных вызов mmap(2) и munmap(2).
Если CLONE_VM не установлен, то потомок будет выполняться в своей отдельной копии адресного пространтсва родителя на время вызова __clone. Запись в память, а также отображение файлов в память теперь выполняется процессами независимо, как в случае с fork(2)
Если CLONE_FS установлен, родитель и потомок используют общую информацию о файловой системе. Сюда входит корневой каталог, текущий каталог и параметр umask процесса. Любой вызов chroot(2), chdir(2), or umask(2), выполненный либо потомком, либо родителем влияет также и на другой поцесс.
Если CLONE_FS не установлен, для потомка создается копия информации о файловой системе родителя но момент вызова __clone. Вызовы chroot(2), chdir(2), umask(2) выполненные процессами не влияют на другой процесс.
Если CLONE_FILES установлен, родитель и потомок будут использовать общую таблицу файловых дескриторов. Эти дескрипторы будут всегда ссылаться на одни и те же файлы и в родительском процессе и в потомке. Любой файловый дескриптор открытый в одном процессе может быть использован в другом. То же самое относится и к закрытию дескриптора с помощью close(2) или изменению его флпгов с помощью fcntl(2).
Еслт CLONE_FILES не установлен, потомок получает копию файловых дескритпоров родителя на момент выполнения __clone. Все операции над фйловыми дескрипторами проводятся процессами независимо друг от друга.
Если CLONE_SIGHAND установлен, родитель и потомок используют общую таблицу обработчиков сигналов. Если потомок или родитель вызывают sigaction(2) чтобы изменить реакцию на сигнал, то эти изменения происходят и в другом процессе. Тем не менее, оба процесса имеют раздельные сигнальные маски. Таким образом, каждый из них может блокировать или разблокировать сигнал используя sigprocmask(2) не влияя на другой процесс.
Если CLONE_SIGHAND не установлен, потомок получает копию таблицы обработчиков синалов на момент вызова __clone. Вызовы sigaction(2) выполненные позже в одном из процессов не влияют на другой.
Если CLONE_PID установлен, потомок получает такой же идентификатор процесса (process ID), что и у родителя. Но использование этого флага не рекомендуется, так как большая часть ПО все еще расчитывает на уникальность идентификаторов процессов.
Если CLONE_PID не установлен, потомок получает свой уникальный идентификатор.
Таким образом, для создания потока нужно задать flags как
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND.
Здесь надо учитывать, что стек на большинстве платформ растет вниз, т.е. в качестве параметра child_stack надо передавать верхний адрес выделенного адресного пространства.
Согласно POSIX, системный вызов fork(2) создает новый процесс состоящий только из одного потока, а именно копии того, что вызвал fork(). ( В так называемых UI threads имеется версия fork() создающая полную копию процесса со всеми потоками). Здесь надо не забывать о том, что если в другом потоке какой-либо мутекс был заблокирован, то он останется навсегда заблокирован и в новом процессе. Чтобы избежать этого следует использовать функцию pthread_atfork(2).
Использование сигналов в многопоточном приложении является не очень хорошей идеей. Чем меньше их смешивать, тем лучше. Тем более в linuxthreads есть некоторые отклонения от стандарта POSIX.
Как известно потоки создаются с помощью вызова clone(2), где в параметрах указывается, что потоки имеют общую таблицу обработчиков сигналов, однако потоки в линуксе, с точки зрения ядра — это процессы, а следовательно каждый сигнал имеет своей целью вполне конкретный идетификатор процесса. Попробуйте, например создать программу из двух потоков, в каждом из потоков запустить интервальный таймер процесса с помощью setitimer(2), например, ITIMER_REAL. По истечению заданного интервала ядро пошлет сигнал SIGALRM, который обработается в указанном вами обработчике, но особенность здесь в том, что у каждого потока свой таймер, соответсвенно SIGALRM будет посылаться обоим потокам, но обрабатываться одним обработчиком, и разобраться какой собственно таймер сработал не всегда бывает просто (можно использовать идетификаторы процессов, соответсвующие работающим потокам).
Во время написания и отладки программы в случае возникновения ошибки сегментации ядро посылает процессу сигнал SIGSEGV, действием по-умолчанию для которого является завершение процесса с созданием core dump — образа памяти процесса. Этот файл удобно использовать для postmorten анализа, чтобы найти причину ошибки. В случае пногопоточного приложения иногда бывает так, что core dump не создается. Причиной для этого могут быть системные ограничения на размер core файла, устанавливаемые вызовом setrlimit(2). Однако стоит заменить обработчик SIGSEGV на следующий:
Имеет смысл в работающей версии запретить создание core файла с помощью установок setrlimit(2) во избежание возможности получения доступа к какой-нибудь закрытой информации, находившейся в памяти процесса.
Здесь хочется напомнить то, о чем многие забывают работая с Posix threads вообще, а не только с Linuxthreads. Речь идет о thread cancelation, т.е. о прекращении выполнении потока из другого потока с помощью pthread_cancel(). При этом зачастую забывают о стековых обьектах, а при thread cancelation стек не раскручивается. Пример программы, содержащей ошибку приведен ниже. Здесь создается обьект класса A (переменная a) на стеке потока, но в результате вызова функции pthread_cancel() в первоначальном( родительском) потоке th1 завершается, а деструктор обьекта не вызывается.
Выходом является использование динамической памяти с посчетом указателей и установкой cleanup handlers с помощью pthread_cleanup_push/pop.
Кроме этого, мутекс, заблокированный потоком не разблокируется автоматически при принудительном завершении, что может привести к тупиковой ситуации, если какой-либо другой поток попытается заблокировать этот же мутекс. Разблокирование мутекса также следует «поручить» cleanup hadlers.
В библиотеке linuxthreads имеется несколько функций с суффиксом _np ( non portable ).
pthread_cleanup_push_defer_np(3)
pthread_cleanup_pop_restore_np(3)
pthread_kill_other_threads_np(3)
pthread_mutexattr_setkind_np(3)
pthread_mutexattr_getkind_np(3)
Само по себе использование потоков не всегда приводит к повышению быстродейтсвия программы, ведь если у вас не мультипроцессорная система, то о параллельном выполнении можно говорить лишь с некоторой степенью приближенности.
При создании приложений с использованием linuxthreads не стоит забывать, что каждый поток в линуксе занимает строчку в таблице процессов. Если вы решили использвать сотню а то и больше потоков, лучше попробуйте переделать модель программы. Возможно, постоянное переключение контекста между потоками не приведет к увеличенмю быстродейтвия, а даже и заметно снизит его и увеличит общую загрузку системы — ведь переключение контекста процесса в ядре все-таки достаточно дорогостоящая операция.
Стоит избегать использования в программе мутексов типа PTHREAD_MUTEX_RECURSIVE_NP ( рекурсивных мутексов ), их использование замедляет выполнение программы, поэтому лучше хорошо проработать свой код, чтобы избежать повторного блокирования уже заблокированного в этом потоке мутекса.
Наиболее частым среди начинающих программистов ( по моему мнению из-за простоты реализации ) подходом при создании сетевых приложений является модель один поток на соединение, когда каждое новое сетевое соединение представляет собой синхронный блокирующий сокет, обрабатываемый выделенным потоком.
Простота данного подхода является также причиной довольно частого заблуждения о высокой эффективности данной модели. Однако это не так: поток, заблокировавшийся на сокете будет просто поедать время прцессора, не выполняя никаких полезных функций и главное отнимать время у потоков, сокеты которых имеют данные для считывания (или возможность для записи). Оговорка: если у вас компьютер с 1000-ю процессоров, или просто если у вас потоков меньше чем процессоров, то эта модель еще в принципе обеспечивает достаточную производительность.
Если же вы хотите получить приложение, способное обслуживать тысячи одновременных соединений на обыкновенной машине с одним-двумя процессорами, то необходимо в первую очередь отказаться от использования блокирующих сокетов. При этом используется небольшое автоматически регулируемое (в некоторых предлах) количество потоков, каждый из которых работает с равным количесвом сокетов (например, максимум 64 дескриптора на поток). Выбор сокета производится с помощью системного вызова poll(2). Такая модель достаточно легко портируется на другие системы, однако, в линуксе имеется возможность не опрашивать сокеты, а поручить ядру информировать поток о определенном событии на дескриторе сокета — с помощью команды F_SETSIG вызова fcntl(2) можно установить сигнал, который приэтом событии будет отправляться ядром процессу. Отличие от существующей практически во всех юниксах возможности отправки сигнала SIGIO при установленном флаге O_ASYNC(FIOASYNC) состоит в том, что если обработчик сигнала будет установлен с помощью SA_SIGINFO в sigaction(2), то сокет, изменивший состояние будет указан в параметре si_fd структуры siginfo_t. Данный способ является непереносимым, однока более быстрым чем перебор набора структур pollfd в системном вызове poll, потому как перебор этих структур (а он присходит и в ядре, а потом и в потоке) может занимать немалую долю времени, выделенного ядром потоку (time_slice).
К вопросу производительности следует также отнести и проблемы, описаные в пункте Учет системных ресурсов., так как использование стековых обьектов небезопасно с точки зрения thread cancelation, а использование динамических обьектов (выделение/освобождение памяти с помощью new/delete) менее эффективно. Здесь можно учитывать то, какие функции являются точками выхода ( cancelation points ) — в linuxthreads к таким относятся pthread_join(3), pthread_cond_wait(3), pthread_cond_timedwait(3), pthread_testcancel(3), sem_wait(3), sigwait(3), т.е. можно организовать выполнение программы таким образом, что стековые обьекты уже будут уничтожены к моменту попадание в cancelation point. Естественно, это относится к потокам с PTHREAD_CANCEL_DEFERRED флагом обработки cancelation request, а не PTHREAD_CANCEL_ASYNCHRONOUS.