View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0002241 | Far Manager | Plugins API | public | 2013-01-03 11:55 | 2013-04-28 13:41 |
Reporter | NightRoman | Assigned To | |||
Priority | normal | Severity | minor | Reproducibility | always |
Status | closed | Resolution | no change required | ||
Product Version | 3.0 | ||||
Summary | 0002241: ACTL_GETWINDOWINFO зависает при вызове из DialogAutoCompletion | ||||
Description | Имеется макрос для модуля PowerShellFar плагина FarNet: Macro { area="Dialog DialogAutoCompletion"; description="Far hangs in DialogAutoCompletion"; key="CtrlShiftF9"; action=function() Plugin.Call("10435532-9BB3-487B-A045-B0E6ECAAB6BC", ":>:Show-FarMessage $Far.Line.Text") end; } Его задача - получить и показать содержимое текущего поля ввода диалога. Работает нормально, если область Dialog, и висит, если область DialogAutoCompletion. Что делается в последнем случае. Открываю диалог Apply Command (CtrlG). Набираю что-нибудь, чтобы появилось меню авто дополнения, вызываю макрос. Что делается в FarNet - он пытается получить самиый верхний диалог, чтобы запросить текущее поле ввода и его текст. Для этого получается число окон - оно равно 3 (панели, диалог Apply Command, меню авто дополнения). Начиная с позиции 2 перебираем окна, пока тип не WTYPE_DIALOG. Для окна с индексом 2 ACTL_GETWINDOWINFO отрабатывает, видим, что это не диалог, идем дальше. На окне с индексом 1 ACTL_GETWINDOWINFO зависает. Если делать это не на тестовом плагине, а на FarNet 5.0.31 и PowerShellFar 5.0.34, как описано, то нужны именно эти указанные версии или более поздние. Примечание. Подобная процедура нормально работает для ком.строки, то есть при открытом меню авто дополнения плагин добирается до текста строки и может работать с ним. Far 3.0.3061. | ||||
Tags | No tags attached. | ||||
Build | 0 | ||||
|
Есть чуть проще макрос, если именно этим путем смотреть проблему (одно двоеточие в команде убрано): Macro { area="Dialog DialogAutoCompletion"; description="Far hangs in DialogAutoCompletion"; key="CtrlShiftF9"; action=function() Plugin.Call("10435532-9BB3-487B-A045-B0E6ECAAB6BC", ">:Show-FarMessage $Far.Line.Text") end; } Первый макрос работает с использованием ACTL_SYNCHRO, второй без. Висят оба в описанном сценарии. |
|
Здесь проблема в том, что ACTL_GETWINDOWINFO не из основного потока вызывается, в результате получаем зависание при вызове EnterCriticalSection, для критической секции, в которую уже в основном потоке вошли. |
|
В обоих случаях? Второй-то сценарий (макрос) вроде без ACTL_SYNCHRO работает. И тоже висит. А что делать с этой проблемой? Как-то лечить/обходить в плагине или как? |
|
Или тут потоки с ACTL_SYNCHRO и не связаны? |
|
Да, в обоих случаях вызов не из основного потока идет, если вызывать из основного все должно быть нормально |
|
Может, туплю, но так и не понял, кто "виноват"? И почему нельзя вызывать из неосновного? В PowerShell все скрипты по сути из неосновного вызываются, так устроено ядро PowerShell, и это не поменять. И все работает хорошо, ну кроме этого случая. Кроме того, я упомянул, что не висит, если вызывать в области Dialog, и висит, если вызывать в DialogAutoCompletion. |
|
Понятно, что нельзя Фар АПИ вызывать просто так из *параллельного фонового* потока. Но этого и не делается в моем случае. Когда вызов идет из неосновного потока, то основной остановлен, эта ситуация "thread safe", проблем быть не должно. На форуме уже обсуждали, что ничего нет плохого в неосновных потоках, надо лишь, чтобы основной был либо остановлен, либо из него не должны идти вызовы АПИ. (DrKnS вводил проверкку поток и возврат ошибки, это убрали, потому что неправильное ограничение). Иначе говоря, задача плагина обеспечить, что только один поток работал с АПИ. А основной или нет - неважно. |
|
И еще примечательно, что зависает всегда при втором вызове ACTL_GETWINDOWINFO. Не может же так быть в нормальной ситуации, что один вызов можно делать, а два нет. Если это особая ситуация с DialogAutoCompletion - другое дело. Но это хотелось бы выяснить и задокументировать. А если баг, то, пофиксить, конечно. Кроме того, я попробовал в ShellAutoCompletion тот же макрос и 2 вызова ACTL_GETWINDOWINFO (2 раза $Far.Line.Text): Macro { area="ShellAutoCompletion Dialog DialogAutoCompletion"; description="Sync Far hangs in DialogAutoCompletion"; key="CtrlShiftF9"; action=function() Plugin.Call("10435532-9BB3-487B-A045-B0E6ECAAB6BC", ">:Show-FarMessage ($Far.Line.Text + $Far.Line.Text)") end; } И все работает. Нет, это что-то особенное для DialogAutoCompletion. |
|
DialogAutoCompletion тут ничем принципиально от обычного диалога не отличается, такой же эффект можно получить, например, создав диалог, и, в его обработчике сообщений, создав второй диалог. Теперь, если из другого потока вызвать ACTL_GETWINDOWINFO для первого диалога, получим зависание. Тут дело в том, что в фаре все действия над диалогами синхронизируются с помощью критических секций, в критическую секцию мы входим перед вызовом обработчика сообщений первого диалога, и выйдем из неё теперь только после закрытия второго диалога. Сделано так, как я понимаю, для диалога поиска, он в отдельном потоке создается. В общем, на мой взгляд, проблема тут в плагине, никто ведь не обещал, что вызов из других потоков будет работать, даже если основной в это время ничего не делает. Хотя, может быть, и не стоит обработчики сообщений из критических секций вызывать. |
|
Можно считать это проблемой плагина. Но АПИ-то и нужен, чтобы решать задачи плагинов без проблем плагинов. В общем, диалог из диалога - особая ситуация, тут все не так хорошо, как хотелось бы, так? Ладно, придется избегать тогда. Но поиграюсь еще, у меня есть ведь случаи диалога из диалога, и там все работает, я почти уверен. Мне все равно кажется, что это специфично для авто-дополнения. Иначе я бы давно проблему заметил. А тут решил попробовать работать, не закрывая авто-дополнение, и сразу встал на граблю. |
|
Назапускал несколько тестовых диалогов друг из друга и там в зоне Dialog вызвал макрос. Все работает. Так что это неверно, что диалог из диалога - проблема. Пока проблема наблюдается только при отрытом авто-дополнении. А потому выглядит либо как баг, либо недоработка. Просто никто ранее такой "продвинутый" сценарий еще не пробовал (либо пробовал, но поленился написать). |
|
tst.cpp (2,194 bytes)
#include "plugin.hpp" PluginStartupInfo Info; FarStandardFunctions FSF; // {BDA97483-6268-4CC7-993D-042067AE639F} static const GUID PluginGuid = { 0xbda97483, 0x6268, 0x4cc7, { 0x99, 0x3d, 0x4, 0x20, 0x67, 0xae, 0x63, 0x9f } }; // {2A8D376D-5ABE-4AF1-A9F5-66053F8C9F7F} static const GUID DialogGuid = { 0x2a8d376d, 0x5abe, 0x4af1, { 0xa9, 0xf5, 0x66, 0x5, 0x3f, 0x8c, 0x9f, 0x7f } }; void Dialog(); int cnt=0; DWORD WINAPI ThreadProc(void*) { WindowInfo wi={sizeof(WindowInfo)}; wi.Pos=1; Info.AdvControl(&PluginGuid, ACTL_GETWINDOWINFO, 0, &wi); return 0; } intptr_t WINAPI DlgProc(HANDLE hDlg, intptr_t Msg, intptr_t Param1, void *Param2) { if(Msg==DN_CONTROLINPUT) { const INPUT_RECORD* record=(const INPUT_RECORD *)Param2; if(record->EventType==KEY_EVENT && record->Event.KeyEvent.bKeyDown) { WORD Key=record->Event.KeyEvent.wVirtualKeyCode; if (Key==VK_F1) { if(!cnt) { ++cnt; Dialog(); } else { //ThreadProc(NULL); DWORD tid; HANDLE thr=CreateThread(NULL, 0, ThreadProc, NULL, 0, &tid); WaitForSingleObject(thr, INFINITE); CloseHandle(thr); } } } } return Info.DefDlgProc(hDlg, Msg, Param1, Param2); } void WINAPI GetGlobalInfoW(GlobalInfo *Info) { Info->StructSize=sizeof(*Info); Info->MinFarVersion=FARMANAGERVERSION; VersionInfo ver={0, 1, 0, 1, VS_ALPHA}; Info->Version=ver; Info->Guid=PluginGuid; Info->Title=L"tst"; Info->Description=L"tst"; Info->Author=L"tst"; } void WINAPI SetStartupInfoW(PluginStartupInfo *Info) { ::Info=*Info; FSF=*Info->FSF; } void WINAPI GetPluginInfoW(PluginInfo *Info) { Info->StructSize=sizeof(*Info); Info->CommandPrefix=L"tst"; Info->Flags=PF_DISABLEPANELS; } void Dialog() { FarDialogItem di[]={{DI_DOUBLEBOX, 1, 1, 9, 9}}; HANDLE hdlg=Info.DialogInit(&PluginGuid, &DialogGuid, -1, -1, 10, 10, NULL, di, 1, 0, FDLG_NONE, DlgProc, NULL); Info.DialogRun(hdlg); Info.DialogFree(hdlg); } HANDLE WINAPI OpenW(OpenInfo *OInfo) { Dialog(); return NULL; } |
|
Прикрепил тестовый плагин, на котором я проверял, запускается через префикс tst: потом, после первого F1 создается второй диалог, после второго - висим |
|
Но у меня нет пока проблем при диалоге из диалога. Твой случай может другую "проблему" показывать. В общем, есть над чем подумать тут, кажется. |
|
К вопросу о "тестовых плагинах"... Надо еще постараться плагин написать так, чтобы оригинальная проблема воспроизводилась. В общем, я у себя это дело отключаю через убирание автодополнения в макросе эскейпом. Остальное у меня работает. Так жить можно вполне. Можно считать фичей, только надо это документировать, чтобы писатели плагинов или макросов не совались в темные места напрасно. |
|
Следует понимать, что "Когда вызов идет из неосновного потока, то основной остановлен" - это ни разу не "thread safe" по вполне понятным причинам. Far API не спроектировано для вызова из дополнительных потоков, кроме случаев, оговоренных отдельно. Хотя программного запрета и нет, но корректная работа не гарантируется, всё на свой страх и риск. Поэтому пока что, увы, могу только порекомендовать "а вы так не делайте". |
|
> "Когда вызов идет из неосновного потока, то основной остановлен" - это ни разу не "thread safe" по вполне понятным причинам. Нет, непонятно. Википедия гласит: Потоковая безопасность (англ. thread-safety) — это концепция программирования, применимая к многопоточным программам. Код потоково-безопасный, если он функционирует корректно при использовании из нескольких потоков одновременно. В частности, он должен обеспечивать корректный доступ нескольких потоков к разделяемым данным. Но все равно, как называть. Если будет работать, то у плагинов будет больше возможностей. Если не будет, то не будет :) |
|
> Нет, непонятно. "- Ну вот представь, живешь ты себе, ходишь в институт, учишься, работаешь, а потом однажды просыпаешься... А ты - кот о_О" Это к тому, что доступ к разделяемым данным может быть сколь угодно корректным, но если они будут изменены, а уснувший такого не ожидал, то будет ой. |
|
Ладно, бага или не бага - не суть важно. Важно, как плагину получить работу с диалогом, когда открыто автодополнение. Особенно из PowerShellFar скрипта, который из другого потока работает при остановленном основном (ну или цикл там, главное, что он не зовет Фар АПИ). А также пример lort-а. Там-то висит без всяких потоков вроде (но я не смотрел детально), это ж не PowerShell скрипт. |
|
Подумалось тут. EnterCriticalSection вызывается, и из-за двойного входа случается зависание, дедлок. То есть получается, код все-таки предназначен для вызовов из других потоков (и даже, по идее, фоновых, параллельных, а не просто других). А иначе зачем EnterCriticalSection? |
|
Уточнение. На всякий пожарный. > Если делать это не на тестовом плагине, а на FarNet 5.0.31 и PowerShellFar 5.0.34, как описано, то нужны именно эти указанные версии или более поздние. "Более поздние" не годятся, там зависание устранено ничегонеделанием. |
Date Modified | Username | Field | Change |
---|---|---|---|
2013-01-03 11:55 | NightRoman | New Issue | |
2013-01-03 12:05 | NightRoman | Note Added: 0009911 | |
2013-01-04 14:22 | lort | Note Added: 0009915 | |
2013-01-04 14:31 | NightRoman | Note Added: 0009916 | |
2013-01-04 14:33 | NightRoman | Note Added: 0009917 | |
2013-01-04 14:54 | lort | Note Added: 0009918 | |
2013-01-04 15:15 | NightRoman | Note Added: 0009919 | |
2013-01-04 15:24 | NightRoman | Note Added: 0009920 | |
2013-01-04 15:53 | NightRoman | Note Added: 0009921 | |
2013-01-04 18:56 | lort | Note Added: 0009922 | |
2013-01-04 19:27 | NightRoman | Note Added: 0009923 | |
2013-01-04 20:15 | NightRoman | Note Added: 0009925 | |
2013-01-04 20:42 | lort | File Added: tst.cpp | |
2013-01-04 20:44 | lort | Note Added: 0009926 | |
2013-01-04 21:06 | NightRoman | Note Added: 0009927 | |
2013-01-05 08:33 | NightRoman | Note Added: 0009929 | |
2013-01-05 08:36 | NightRoman | Note Edited: 0009929 | |
2013-01-05 08:38 | NightRoman | Note Edited: 0009929 | |
2013-01-05 09:52 | DrKnS | Note Added: 0009930 | |
2013-01-05 15:33 | NightRoman | Note Added: 0009931 | |
2013-01-05 15:55 | DrKnS | Note Added: 0009932 | |
2013-01-05 17:56 | NightRoman | Note Added: 0009933 | |
2013-01-08 03:22 | NightRoman | Note Added: 0009943 | |
2013-01-15 16:23 | NightRoman | Note Added: 0010009 | |
2013-04-28 13:41 | alexy | Build | => 0 |
2013-04-28 13:41 | alexy | Status | new => closed |
2013-04-28 13:41 | alexy | Resolution | open => no change required |