다솜 입력기 테스트 버전을 준비하고 있습니다.

Sat, Jul 4 2015 16:24:00 KST

안녕하세요…
다솜 입력기를 만들기 시작한지가 벌써 5개월 정도 지났습니다.
최근 입력기 서버 및 im 클라이언트에 있던 굵직한 버그(race condition)를 잡았습니다.
그걸 잡고 나니 focus out / focus in 이 싱크가 안 맞더군요.
자세히 살펴보니…
창이 2개가 있고, 창1에 포커스가 있을 때, 창2번을 찍으면
창1번은 focus out 신호를 발생시키고 focus out 신호에 대한 처리(reset, commit 등)가 완료되지 않아도
창2번은 바로 focus in 신호를 발생시킵니다.
아마도 윈도 관리자가 창관리를 thread로 처리할 것으로 추정됩니다. 그래서 이러한 현상이 나타나는 것 같습니다.
그래서 focus in / out 싱크 맞추기 위해 아래처럼 작성하였습니다.

    case DASOM_MESSAGE_FOCUS_OUT:
      pending = TRUE;
      dasom_context_focus_out (context);
      dasom_send_message (socket, DASOM_MESSAGE_FOCUS_OUT_REPLY, NULL, NULL);
      pending = FALSE;
      break;
...
  if (pending)
  {
    ctx = g_main_context_new ();
    GSource *source = g_socket_create_source (context->socket, G_IO_IN, NULL);
    g_source_set_can_recurse (source, TRUE);
    g_source_set_callback (source, (GSourceFunc) on_incoming_message_dasom, context, NULL);
    g_source_attach (source, ctx);
  }

  do {
    g_main_context_iteration (ctx, TRUE);
  } while (context->reply && (context->reply->type != type));

이것은 완벽한 해결책은 아닙니다. 왜냐하면 서버 엔진의 focus_out 함수에서 signal 을 발생시킨 후 이를 처리하는 클라이언트의 callback에서 아래처럼 비정상적으로 호출할 경우 문제가 발생할 수 있기 때문입니다.
또한, engine의 caller (target context)가 변경이 되기 때문입니다.

void client_signal_callback (im1)
{
  dasom_im_some_api (im1); /* fd: 38 이런 건 문제가 되지 않습니다. */
  dasom_im_some_api (im2); /* fd: 39 이렇게 im1과는 다른 im2를 호출하는 경우 문제가 됩니다 */
}

위의 같은 코드를 허용하려면 현재 모듈별로 engine 인스턴스가 1개만 생성되는 싱글톤 방식인데, 클라이언트 context 당 1개씩 생성하도록 변경하면 해결이 되지만, 이 경우 클라이언트/서버 구조로 만들 필요도 없어지고 그냥 일반적인 라이브러리 호출로 작성하고 엔진이 변경될 때 입력기 상태 알림 agent 서버에 한/영/중/일 엔진 상태를 알려주도록 만들면 되겠죠.
그런데 왜 서버 구조로 만들었냐면, 응용 프로그램이 im_context를 여러개를 생성하기 때문에 응용 프로그램 당 im_context를 5개씩 생성한다고 가정하면, 응용 프로그램을 5개(웹 브라우저, 편집기, 파일 관리자, 음악 플레이어, 터미널) 정도 실행시키면 25개 정도의 im_context가 생성되는데 한국어의 경우 별로 부담이 되지는 않지만, 중국어, 일본어의 경우 로딩되는 사전 파일의 크기가 커서 시스템에 큰 부담이 되기 때문에, 서버측의 엔진 인스턴스를 엔진 모듈당 1개만 생성(싱글톤 방식)하도록 설계하였습니다.
그래서 엔진 인스턴스 1개로 여러 프로그램이 사용을 하게 됩니다. 예를 들어 한국어의 경우, 응응 프로그램을 5개를 실행시키더라도 서버측 엔진은 1개만 생성됩니다. 기존의 라이브러리 방식이라면 약 25개가 생성이 되겠죠.
그리고 우리가 입력을 할 때 창이 5개가 있다면 키보드 5개로 5개의 창에 동시 입력을 하는 것이 아니라, 5개의 키보드가 있다고 하더라고 키보드 1개로 촛점이 잡힌 1개의 창에 입력을 합니다. 그래서 다솜 입력기에 스레드를 사용하지 않았습니다. 스레드를 사용해봤자 얻을 수 있는 이득이 없습니다.
저 혼자 알파 테스트를 좀더 거친 후에, 반드시 필요한 최소한의 기능을 갖춘 후, 보다 폭넓은 베타 테스트를 하기 위해 테스트 버전을 조만간 만들 계획입니다.


hodong 2015-07-05 21:09

다 되었다고 생각했는데… 다시 원점으로 돌아가게 되는군요…
테스트를 하면서 창을 전환하다보니 focus out 다음에 focus in 신호가 발생해야 하는데…
어떤 경우는 focus in 이 먼저 발생되고 그 다음에 focus out 신호가 발생되기도 합니다.
이런 경우 처리가 애매한데… 서버에서 focus in 신호를 받아서 focus out 신호를 받을 때까지 지연시키면 되겠지만, 클라이언트 프로그램을 강제로 죽일 경우, 서버가 focus out 신호를 받지 못하여 서버가 무한 루프에 빠지고, focus in 신호를 보낸 클라이언트는 무한 대기를 하는 경우가 발생합니다.
역시 해결이 쉽지 않은 부분이네요…
마땅한 해결책이 없는데…ㅠㅠ
메시지 큐, 스레드..를 사용해도 마찬가지 결과가 나올 것으로 예상되는데…
XIM 프로토콜처럼 패킷에 client id, context id 를 실어서 보내야 할까요.


hodong 2015-07-06 05:01

지금까지 발견한 문제점은 모두 해결된 것 같네요.
target context를 지정하는 방법을 좀 바꾸었습니다.
뭐… 그래서… 엉뚱한데다가 메시지 보내는 문제점 해결했고,
pending focus out 문제가 조금 거슬리지만,
테스트할 때 오류 있는 im 클라이언트에 ALT + F2 + r 열심히 눌러데서… 발생한 문제라…
그런 상황이 거의 발생이 안 되는 부분이니,
timeout 걸어놓으면 실제 사용에는 문제가 없을 것 같네요.
이정도만 되어도 기존 입력기들보나 좋으니..ㅋㅋ
아휴…. 이 문제 해결하다가.. 날 샜네요.. ㅠㅠ


hodong 2015-07-07 00:43

텍스트 입력창을 4개 정도 열은 후에, 마우스로 그 중 한 창을 클릭해서 초점을 맞추고 텍스트 입력할 수 있는 상태가 되도록 한 후,
ALT + F2 + r 누를 경우, gnome-shell extension 이 재시작되는데…
아까 초점이 맞춘 창은 FOCUS IN / FOCUS OUT 신호가 발생되지 않는 버그가 있습니다.
다솜 입력기를 제거한 후 imhangul를 가동시킨 후에도 재현됩니다.
아마, gnome-shell 의 버그로 추정됩니다. 아휴…
또한, gedit에서 Git 플러그인을 활성화시킨 후에, git clone 하여 받은 파일을 열은 후에
“가나 다” 이렇게 입력하고 백스페이스를 누르면 공백이 먼저 삭제된 후 ㅏㄷ 이렇게 삭제됩니다.
imhangul로 해봐도 동일한 증상이 있는 걸로 봐서 gedit (Git 플러그인) 버그로 추정됩니다.
현재 다솜 입력기를 메인으로 사용하고 있는데 별다른 특이점은 발견되고 있지 않습니다.
아직 커밋하지 않은 코드가 2개가 있는데,

  1. target context 변수를 지정하는 방법을 변경한 코드를 테스트 중이고,
  2. im1(가명)이 FOCUS_OUT 중일 때 FOCUS_OUT 이 끝날 때까지 im1 소켓만 읽는 코드가 있는데 주석처리 해놓았습니다. FOCUS_OUT 이 처리 중일 때, FOCUS_IN 메시지를 받으면 서버는 그걸 처리하게 되는데, FOCUS_IN 에 RESET 이런 게 FOCUS_OUT 에서 처리하는 것보다 먼저 처리하게 되면 끝글자가 마우스로 클릭하는 곳에 찍힐 수 있습니다. 2번 코드는 이것을 해결하는 코드이지만, race condition 이 발생할 우려가 생기게 됩니다.

2번의 주석 처리해 놓은 코드를 사용하게 되면
서버가 im1이 보낸 FOCUS_OUT을 처리 중일 때 RESET 하여 im1 에 commit 신호를 보낼 경우,
클라이언트의 im1 commit 콜백 내에서 im2가 서버에 메시지를 보내면,
서버는 im1 소켓만 읽고 있는 중이므로 im2가 보낸 REPLY 메시지를 받지 못하여 무한정 기다리게 됩니다.
클라이언트는 FOCUS_OUT_REPLY 메시지를 무한정 기다리게 되어, 한마디로 먹통이 됩니다.
이런 걸 race condition 이라고 합니다.

이것을 방지하는 방법이 있습니다. 서버가 im1 소켓에서만 읽고 있으므로 im2 소켓에 도착한 것을 읽지를 못합니다. 따라서 im 라이브러리에서 im1 callback 내에 im2가 사용되면 이를 감지하여 im2를 async 동작시키면 됩니다. 경고 메시지도 출력해야겠죠. 좀 난해하지만, loop 구조(마치 스택 같음)로 되어 있으므로 감지가 가능할 것 같습니다. 6월 초 쯤에 감지 코드와 async 코드가 있긴 있었죠. 커밋도 하지 않고 다 삭제해서 지금은 없지만요.

여기까지 하면 싱글톤 방식이기 때문에 어쩔 수 없는 경우를 제외하고는 race condition 이 완전히 해결될 것 같습니다. 응용 프로그램이 항상 정확한 동작을 하는 것은 아니기 때문에 그 어쩔 수 없는 경우는 timeout을 둠으로써 해결이 되겠죠.

2번, 3번 코드는 나중에 필요하면 사용하도록 하고,
1번을 사용하면서 나머지 구현 못한 부분들(XIM, 한자 창, 엔진 설정 방법, 상태 표시기, 서버 재가동 코드, 재접속 코드 등)을 구현하고자 합니다.

지금 메인 입력기로 다솜 입력기를 사용하고 있는데 잘 작동하고 있습니다.
한글 입력이 편리하게 잘 되어 행복합니다.


hodong 2015-07-21 08:15

제가 알고 있는 엔간한 버그를 다 잡은 것 같습니다.


hodong 2015-07-21 23:21

제가 알고 있는 버그는 모두 잡은 것 같습니다.
이제 드디어 테스트 가능한 상태가 되었습니다.

자질구레한 작업들만 남았습니다.
예를 들자면,
.deb 제작용 debian 파일, 설정 창, 한자 창 더 이쁘게 보이기, 조합 중인 상태 색깔, 예외 처리 방법 등.
엔진 개발을 위한 api 다듬기, agent / candidate interface 설계 등.
아.. 나중에 시간 날 때 qt 용 모듈 및 중국어, 일본어 엔진들도 만들어야 하는군요.

초보자 분들은 따라하시면 스트레스 좀 받으실겁니다.
설치는

./autogen.sh

에러 발생시 필요한 패키지 설치.

make
sudo make install
sudo ldconfig
im-config

하면 창이 뜰텐데 Dasom 선택
윈도 logout
다시 윈도 login

프로젝트 주소
https://github.com/cogniti/dasom

버그, 기능 개선, 희망 사항 등은 아래 주소에 글을 남겨주세요.
https://github.com/cogniti/dasom/issues


hodong 2015-07-23 12:34

README 파일에도 써놓았는데… gtk 모듈 캐시 업데이트하는 걸 깜박했네요…

환경에 따라 명령어 찾는 방법을 만들 시간 없으니
나중에 아래 부분을 하드코딩해서 Makefile.am 에 넣어야겠군요.

32비트

sudo /usr/lib/i386-linux-gnu/libgtk-3-0/gtk-query-immodules-3.0 --update-cache
sudo /usr/lib/i386-linux-gnu/libgtk2.0-0/gtk-query-immodules-2.0 --update-cache

64비트

sudo /usr/lib/x86_64-linux-gnu/libgtk-3-0/gtk-query-immodules-3.0 --update-cache
sudo /usr/lib/x86_64-linux-gnu/libgtk2.0-0/gtk-query-immodules-2.0 --update-cache

hodong 2015-07-23 21:48

오늘 iceweasel 로 탭 5~10개 정도 띄어놓고 사용하던 중에 focus-in 하니 입력기 먹통되었습니다. 게다가 프로그램 실행까지 안 되더군요. 스님이 자기 머리 못 깎는 것처럼, 다솜 입력기를 개발하면 다솜 입력기 사용을 하지 못하는 아… 이런 슬픈 상황 발생. ㅠㅠ 그래서 G_DEBUG 를 켜놓고 돌려버렸습니다… 로그 엄청… 쌓일텐에…ㅠㅠ


hodong 2019-03-31 17:48

세월 참 빠르군요..
프로젝트 주소 변경되었습니다.

https://gitlab.com/nimf-i18n/nimf