Archive for the ‘Код и программистское’ Category

iOS тайно-скрытные API

Четверг, Август 9th, 2012

Люди, а часом никто не копался с

a) iOS Private API

b) Jailbreak development

Если есть такие, черкните мне (victor dot ronin at gmail dot com). С удовольствием бы пообщался по этому поводу, плюс попоил бы пивом/соком/авиационным топливом (по выбору).

Кстати, чтобы два раза не бегать. Вот тут вот на StackOverflow пытаюсь создать раздел специально под это заточненный. Если не трудно, подпишитесь, чтобы они его таки создали.

 

По пути наибольшего сопротивления.

Пятница, Апрель 1st, 2011

У меня такое впечатление, что у меня где-то в генокоде прописано то, что я постоянно в программировании двигаюсь по пути наибольшего сопротивления.

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

Сегодняшний пример.
Мне нужно написать небольшой Servlet (условно говоря 1 страница кода) и отмерять jMeter’ом его быстродействие. Ну блин, что может быть проще?

Ан… нет. Учитывая, что сервлеты я писал дааавно (да и JSP’шки, разве что самые простенькие делал), то естественно я успел наткнуться на странные грабли.

Посылаю POST (из jMeter), а в Servlet приходит GET. Ладно, сделал HTML, посылаю форму POST, все равно зараза приходит GET. В общим, в инете рылся, ничего не нашел по этому поводу. Плюнул, Нашел пример сервлета, запустил — для него таки приходит POST.

Ok. Ищем разницу. Нашел таки. Оказывается, в порыве страсти, когда я делал servlet-mapping, то url-pattern я указал «/»
Соотвественно, весь URL у меня должен выглядеть так «http://localhost:8080//». А я вместо этого и в jMeter и в HTML написал «http://localhost:8080/» (без последнего слеша).

И вот эта зараза, вместо того, чтобы послать меня нафиг или работать нормально, решила, что вместо POST, она будет делать GET, а все параметры выкинем в окно.

Бац-бац-бац головой об стену.

Доктор, дайте мне пилюль от граблей.

Вопрос по JNI и JEE к джавистам.

Среда, Март 23rd, 2011

Условия:
а) Есть DLL в которой нужная нам функциональность
б) Есть самописанная JNI обертку (проверил на JSE — работает на ура)
в) Есть JBoss на виндах

Вопрос:
в) Как бы по правильному использовать JNI в JEE envinronment (под JBoss).

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

Из того, что я прочел и понял
— Если у нас что-то крешится в DLL, то падает весь сервер.
— Если Java класс делающий System.LoadLibrary загружен одним ClassLoader’ом, то если второй ClassLoader попытается
загрузить тот же класс, то оно не сможет загрузить DLL, так как DLL уже загружен в процессе (особенность винды) и поэтому не сможет использовать JNI интерфейсы.
— Как я понял, по спецификации EJB не работают с JNI. С другой стороны, в нескольких местах прочел, что работаю, но с ограничениями.

Пару идей которые встречал
а) Сделать C++ приложение JMS enabled. И общаться из приложения в app server с этим JMS enabled приложение
б) Поднять отдельный сервер и общаться через RMI.
в) Сделать adaptor (JavaEE connector architecture). Это опцию я понял хуже всего, но зато похоже она наиболее правильная.

Ну и еще раз повторю вопрос, только теперь чуть более развернуто. Как бы сделать это по правильному? Какие есть еще подводные камни о которых нужно знать (так как хочется не только сделать правильно, но и понимать, почему это правильно).

По следам опыта создания DLL’ек.

Пятница, Март 18th, 2011

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

Ну, это естественно на бумаге, а в жизни, как оказалось множество оврагов. Очень быстро и поверхностно (все пишется с точки зрения C/C++, но на самом деле актуально фактически для всего из чего можно собрать DLL)

— Ну начнем с простого факта. В DLLMain нельзя делать много из того, что можно делать в многих других местах.
а) Вызывать LoadLibrary, FreeLibrary
б) Работать с Registry
в) Работать с потоками и процессами. (Создавать потоки можно, но ждать их нельзя)
г) Использовать API, которые предоставляются не Kernel32.dll
д) И само собой нельзя делать все то, что использует вышеперечисленные вещи. Например нельзя использовать COM

— Увы, факт ограничений в DLL написал маленькими буквами где-то на 5 странице документации. Еще хуже то, что зачастую все будет работать нормально, до тех пор пока вам какой-нибудь заказчик не пришлет баг, которые повторяется в 30% случаев, когда луна находится в перегелии и не зная этих ограничений можно долго и счастливо все это дебажить.

— Ладно. С ограничениями разобрались. Если нам что-то надо будет сделать, мы создадим потом, который сделает эти операции или сделаем глобальную переменную объекта, в конструкторе которого сделаем все что нам надо. Правильно? Бззззз… Ответ не правильный.
а) Если мы создаем поток и не ждем его (так как ждать нельзя), мы не можем быть уверенными что DllMain уже закончится, так что мы просто создали race condition и проблемы стали еще более тяжело воспроизводимы
б) Глобальные переменные и статические члены классов инициализируются и деинициализируются внутри DllMain. Хотя это с ходу не видно, но если полезть в CRT, то это станет понятно. Таким образом, описанные ограничения касаются также конструкторов и деструкторов.

— Итого, имеем, чтобы по честному сделать какую-ту серьезную инициализацию, то нужно иметь функцию в нашей DLL которую клиент вызовет и там мы сделаем все сложные действия. Аналогично, кстати для деинициализации.

— Особенно все прикольно становится, когда мы пишем DLL которую будет впихивать в чужие процессы с помощью SetWindowHookEx или просто plugin’ы к какой-то системе. В обоих случаях, интерфейс может быть заранее определен и там нету функций инициализации и деинициализации. Соотвественно, не ясно что делать.

— Ok. Поздняя инициализация нам поможет насчет инициализации. То есть когда-то кто-то вызовет первый из интерфейсов, мы сделаем все сложные действия. А что делать с деинициализацией? В отличии поздней инициализации, ранней деинициализации не существует то? На это увы, общего ответа я не нашел и в каждом случае, нужно искать свое решение.

— Следующая особенность состоит в том, что все потоки созданные в DLL на самом деле принадлежат процессу. То есть если вдруг DLL будет выгружена из памяти (потому что вызывающий процесс сделал FreeLibrary и DLL counter стал равным 0), то внезапно адресное пространство где была DLL будет высвобождено. А поток останется __ЖИВ__. То есть он попытается выполнить свою следующую операцию, для этого попытается считать следующую команду из адресного пространства где была DLL и мгновенно закрешится. Скажите прекрасно?

— Ok. То есть нам надо остановиться все потоки, которые мы создали в DLL перед тем, как она будет выгружена и это при том, что мы еще даже точно не знаем, как нам запустить какой-то код перед выгрузкой, причем в момент, где нет ограничений. А да, и я еще молчу о том, что написать нормальный thread manager который обрабатывает достаточно большое количество разных ситуаций не вызывая dead lock’ов и race condition, задача в целом не тривиальная.

— Так… Что там у нас дальше. Ага. Вам нужно использовать COM? Само собой вы привыкли к CoInitialize(Ex) и побежали. Только вот, есть одна проблема. Если вы это делаете в DLL то вы исполняетесь в чужом потоке и у потока уже может быть инициализирован COM, причем не в том режиме (STA vs MTA) в котором вам нужно. Что делать? Создавать отдельный поток в котором выполнять все COM действия.

— Единственное пожалуй из положительного. Многое из того, что я писал относится к выгрузке DLL системой. Есть простой трюк, как удостовериться, что система никогда не выгрузит ваш DLL (исключая закрытие программы). Все что вам нужно сделать в DLL это вызывать GetModuleHandle(Ex). Это добавит 1 к DLL counter’у и можно не беспокоиться, что counter когда-либо вернется к нулевому значению.

— А еще во время выхода из процесса, система убивает все потоки, причем поток мог быть посередине модифицирования каких-нибудь данных (внутри критической секции). Еще приятней то, что он мог быть внутри функции работы с heap и таким образом heap будет в inconsistent state. И поэтому лучше не делать ничего хитрого (а по возможность вообще ничего) в DLLMain DLL_PROCESS_DETACH и в деструкторах глобальных объектов (взято отсюда: http://blogs.msdn.com/b/oldnewthing/archive/2007/05/03/2383346.aspx

Вроде все, хотя может что-то еще вспомню.