kakao_pidgin 프로젝트 시작.

오픈소스 프로젝트를 시작했다.
카카오톡 플러그인 for pidgin..

뭔가 거창하지만 실상은 리눅스에서 카카오톡 하기.

이미 wine을 이용한 리눅스에서 카카오톡 사용하기가 나와있는 상태에서 그다지 쓸모는 없을 꺼 같지만..
순전히 재미삼아 만들어보기로 한다.

무엇보다.. wine을 별로 안 좋아하는 나로서는, 여자친구와 카톡을 하기위해서 매번 버추얼 박스를 사용하고 있는데 이게 굉장히 불편하고 귀찮다.
또한, 카카오톡 메시지 수신 알람을 알아채기도 힘들고…

그래서 만들기로 한다.

… 할 수 있을까를 고민하기보단, 한번 해보는데 더 힘을 쏟자.

rtl8723ae driver in Gentoo

노트북에 젠투 설치 후, 부팅을 하면 이상하게 무선랜이 안잡히는 현상이 발생했다.
처음 설치할 당시, USB로 부팅 했을 때에는 잘 잡히던 무선랜이 USB 제거 후, 노멀부팅을 하면 안잡히는 것이다.

혹시나 커널 컴파일 할 때, 깜박하고 해당 모듈을 설치 안한건 아닐까 싶어서 확인을 해 봤으나 이미 설치가 되어있는 상태였다.

pchero@localhost /usr/src/linux $ grep 8723 .config
CONFIG_RTL8723AE=y

먼저 dmesg 로 어디가 문제인지를 살펴보았다.

다음의 부분이 확인되었다.

[    0.316869] pci 0000:02:00.0: [10ec:8723] type 00 class 0x028000
[   13.595185] usb 2-1.3: New USB device found, idVendor=0bda, idProduct=8723
[   17.805554] rtl8723ae: Using firmware rtlwifi/rtl8723fw_B.bin
[   17.805585] rtl8723ae 0000:02:00.0: Direct firmware load failed with error -2
[   17.805588] rtl8723ae 0000:02:00.0: Falling back to user helper
[   17.806024] rtlwifi: Firmware rtlwifi/rtl8723fw_B.bin not available

마지막 라인. rtlwifi: Firmware rtlwifi/rtl8723fw_B.bin not available 즉, rtlwifi/rtl8723fw_B.bin파일이 없다는 것이다.

왜 없을까… 이유는 둘째치고 일단 해당 파일을 구해보기로 했다.

git 명령으로 구할 수 있다.

git clone git://git.kernel.org/pub/scm/linux/kernel/git/dwmw2/linux-firmware.git /lib64/firmware/

이후 재부팅시 해당 모듈이 정상적으로 올라오는 것을 확인할 수 있다.
하지만 dmesg 내용을 확인해 보면 역시나 같은 오류 메시지를 확인할 수 있다.

localhost ~ # dmesg |grep 8723
[    0.316576] pci 0000:02:00.0: [10ec:8723] type 00 class 0x028000
[    2.257211] rtl8723ae: Using firmware rtlwifi/rtl8723fw_B.bin
[    2.258245] rtl8723ae 0000:02:00.0: Direct firmware load failed with error -2
[    2.259305] rtl8723ae 0000:02:00.0: Falling back to user helper

어찌된 일일까? 아마도 Direct firmware 로그는 실패했지만, rtlwifi 모듈이 정상적으로 올라와서 그런거 같다.

[   17.475458] rtlwifi: wireless switch is on

debuginfo-install

man debuginfo-install

debuginfo-install(1)                                      debuginfo-install(1)

NAME
debuginfo-install

SYNOPSIS
debuginfo-install package

DESCRIPTION
debuginfo-install  is  a  program  which  installs the RPMs needed to debug the specified package.  The package argument can be a wildcard, but will only match installed pacakges.  debuginfo-install will then
enable any debuginfo repositories, and install the relevant debuginfo rpm.

EXAMPLES
Download and install all the RPMs needed to debug the kernel RPM:
debuginfo-install kernel

WARNING MESSAGES
Could not find debuginfo for:
if you run debuginfo-install for a wildcard or glob. Debuginfo packages are not necessary for “noarch” RPMs; these will generate a warning message.  Additionally, On 64-bit systems, no multilib  debug-
info packages are published, so if you have 32-bit packages installed, these will also generate warning messages.

FILES
As debuginfo-install uses YUM libraries for retrieving all the information, it relies on YUM configuration for its default values like which repositories to use. Consult YUM documentation for details:

/etc/yum.conf
/etc/yum/repos.d/
/var/cache/yum/

SEE ALSO
yum.conf (5)
http://yum-utils.baseurl.org/
http://yum.baseurl.org/

AUTHORS
See the Authors file included with this program.

BUGS
There  are  of  course  no bugs, but should you find any, you should first consult the FAQ section on http://yum.baseurl.org/wiki/Faq and if unsuccessful in finding a resolution contact the mailing list: yum-
devel@lists.baseurl.org.  To file a bug use http://bugzilla.redhat.com for Fedora/RHEL/Centos related bugs and http://yum.baseurl.org/report for all other bugs.

James Antill                    21 October 2008           debuginfo-install(1)

debuginfo-install 명령어는 rpm/yum 으로 설치한 바이너리 패키지들이 crash dump 가 발생했을 때, gdb를 이용하여 디버깅을 할 때 필요한 패키지들을 설치하는 명령어이다.
물론, rpm/yum 으로도 해당 패키지들의 설치가 가능하다. 단, 정확한 패키지명을 입력해야만 한다.

마찬가지로, ubuntu 에서도 apt-get 으로 설치한 패키지들의 디버깅을 위한 debuginfo 패키지를 제공한다.
그러나, debuginfo-install 명령으로 설치하는 것이 아닌 apt-get 명령어로 설치해야 한다. 설치해야되는 debug 패키지들의 패키지 명은 패키지명-dbg 로 입력하면 된다.

현재 회사에서는 개발된 제품들을 배포할때 rpm으로 제작하여 배포를 한다.
이렇게, rpm 으로 제작된 패키지들에 대하여 코어 파일이 발생하고, 디버깅을 해야 할 때, 앞서 언급한 debuginfo 패키지를 설치한 뒤, 디버깅을 한다.

이렇게 작업을 하게 되면, 디버깅을 할 때, 별도의 소스코드 없이도 rpm 패키지들로만으로도 코어 분석이 가능하게 된다.

setting of remote system environment for eclipse

원격지에서 ssh 통신으로 접속해서 작업을 하는데 eclipse 연동으로 작업을 하고 싶다면???

ssh key 복사 + sshfs + eclipse  구성이 정답이다.

ssh key 복사를 통해, ssh 접속시 비밀번호를 입력하지 않고도 바로 접속이 되도록 설정하고, sshfs 로 원격지 파일 시스템을 로컬 파일 시스템에 마운트한다.
그 다음, eclipse 를 통해 작업을 하는 것이다.

먼저 비밀번호 없이 ssh 로 접속하는 설정이 필요하다.다음을 참고하자.

http://pchero21.com/3034

이제 sshfs 를 구성하자. 아직 sshfs 가 설치되어 있지 않다면 다음의 명령어를 입력하자.

$ sudo apt-get install sshfs

이제 작업 공간 디렉토리를 마운트 시키자.

sshfs stk@test_server:absoulte_work_directory_path_of remote absoulte_mount_position_of_local

이제 eclipse 로 프로젝트를 하나 생성해서 프로젝트 위치를 방금 마운트 한 곳으로 지정하자.

그리고, 생성한 프로젝트에서 C/C++ Build -> Builder Settings -> Build command 항목을 아래와 같이 수정해주자.

ssh pchero@10.0.6.12 ‘bmake -C Absolute_path_for_working_directory_of_remote’

이제 프로젝트를 빌드할 때, 원격지에서 빌드를 수행하는 것을 확인할 수 있다.(필자는 bmake 를 사용하므로 bmake를 입력했다. 만약 gnu-make 를 사용한다면 그냥 make를 입력하도록 하자.)

한가지 단점이라면, 구성 자체가 ssh로 먼저 접속을 한 다음, 뒤따라오는 명령어를 수행하는 방식이기 때문에…
매번 빌드를 할 때마다 ssh 접속 오버헤드가 발생한다는 점이다.

ssh 는 RSA 키 조합의 특성으로 접속시 다소 시간이 오래 걸리는 편이다. 때문에 필자의 경우, sshfs를 통한 파일시스템 마운트 후, 빌드는 ssh 를 통하지 않고, 로컬 머신에서 하는 것으로 구성했다.

출처: http://sunjinyang.wordpress.com/2008/08/11/eclipse-with-remote-ssh-server/

Libevent event driven memory leak

진행중인 프로젝트에서 Libevent 를 사용중인데.. valgrind 메모리 누수 확인시 자꾸 메모리 누수가 발생하는 것을 확인했다.

어디가 문제일까… 기능상으로는 문제가 없었다.
malloc/calloc 할당한 부분도 문제가 없었다.
valgrind 가 지목한 문제 발생한 부분은 event_new() 부분이었다.

문제 발생 원인은 잘못된 libevent 사용에 있었다.
나는 다음과 같이 프로그램을 개발했었다.

/*
* main.c
*
* Copyright 2014 Sungtae Kim <pchero21@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <event2/event.h>

typedef struct _wctx
{
struct event_base*  w_base;     // main base
} wctx;

static void cb_main_listen(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg);
static void cb_process(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg);
static void cb_process_detail(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg);

int main(int argc, char **argv)
{

wctx* work = calloc(1, sizeof(wctx));

work->w_base = event_base_new();
struct event* main_listen = event_new(work->w_base, STDIN_FILENO, EV_READ, cb_main_listen, work);
event_add(main_listen, NULL);

event_base_dispatch(work->w_base);

printf(“System terminate…n”);
event_free(main_listen);
event_base_free(work->w_base);

return 0;
}

static void cb_main_listen(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg)
{
wctx* work = (wctx*)arg;
struct event* w_event = evtimer_new(work->w_base, cb_process, work);

struct timeval  tVal;
tVal.tv_sec = 0;
tVal.tv_usec = 0;
evtimer_add(w_event, &tVal);
}

static void cb_process(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg)
{
printf(“Process!!n”);
wctx* work = (wctx*)arg;
struct event* w_event = evtimer_new(work->w_base, cb_process_detail, work);

struct timeval  tVal;
tVal.tv_sec = 0;
tVal.tv_usec = 0;
evtimer_add(w_event, &tVal);

}

static void cb_process_detail(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg)
{
printf(“Detail Process!!n”);
}

 

아래는 valgrind 로 메모리 누수를 확인한 내용이다.

pchero@MyGalaxy:~/workspace/Study/Program/LibEvent/memory_leak$ echo “Hello” | valgrind –leak-check=full ./main
==2222== Memcheck, a memory error detector
==2222== Copyright (C) 2002-2012, and GNU GPL’d, by Julian Seward et al.
==2222== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==2222== Command: ./main
==2222==
Process!!
Detail Process!!
System terminate…
==2222==
==2222== HEAP SUMMARY:
==2222==     in use at exit: 280 bytes in 3 blocks
==2222==   total heap usage: 12 allocs, 9 frees, 1,848 bytes allocated
==2222==
==2222== 136 bytes in 1 blocks are definitely lost in loss record 2 of 3
==2222==    at 0x4C2A2DB: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2222==    by 0x4E43A46: event_new (in /usr/lib/x86_64-linux-gnu/libevent-2.0.so.5.1.9)
==2222==    by 0x400A16: cb_process (main.c:73)
==2222==    by 0x4E41F93: event_base_loop (in /usr/lib/x86_64-linux-gnu/libevent-2.0.so.5.1.9)
==2222==    by 0x400933: main (main.c:49)
==2222==
==2222== 144 (136 direct, 8 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 3
==2222==    at 0x4C2A2DB: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2222==    by 0x4E43A46: event_new (in /usr/lib/x86_64-linux-gnu/libevent-2.0.so.5.1.9)
==2222==    by 0x4009A1: cb_main_listen (main.c:61)
==2222==    by 0x4E41F93: event_base_loop (in /usr/lib/x86_64-linux-gnu/libevent-2.0.so.5.1.9)
==2222==    by 0x400933: main (main.c:49)
==2222==
==2222== LEAK SUMMARY:
==2222==    definitely lost: 272 bytes in 2 blocks
==2222==    indirectly lost: 8 bytes in 1 blocks
==2222==      possibly lost: 0 bytes in 0 blocks
==2222==    still reachable: 0 bytes in 0 blocks
==2222==         suppressed: 0 bytes in 0 blocks
==2222==
==2222== For counts of detected and suppressed errors, rerun with: -v
==2222== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 2 from 2)

메모리 누수가 확인되는 지점이 두 곳이 보인다. 모두 event_new 를 했던 곳이다. 내용인즉, event_new() 를 통해 생성한 event를 따로 정상 삭제하지 않았다는 내용이다.
나는 timer 에 등록할 경우, 시간이 되어 함수가 작동할 경우, libevent 에서 자동으로 메모리를 해제해 주는 줄 알았다.
하지만 아니었다…

결국, 소스를 다음과 같이 수정하였다.

/*
* main.c
*
* Copyright 2014 Sungtae Kim <pchero21@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <event2/event.h>

typedef struct _wctx
{
struct event_base*  w_base;     // main base
struct event*       w_event;    // work event
} wctx;

static void cb_main_listen(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg);
static void cb_process(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg);
static void cb_process_detail(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg);

int main(int argc, char **argv)
{

wctx* work = calloc(1, sizeof(wctx));

work->w_base = event_base_new();
struct event* main_listen = event_new(work->w_base, STDIN_FILENO, EV_READ, cb_main_listen, work);
event_add(main_listen, NULL);

event_base_dispatch(work->w_base);

printf(“System terminate…n”);
event_free(main_listen);
event_base_free(work->w_base);
free(work);

return 0;
}

static void cb_main_listen(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg)
{
wctx* work = (wctx*)arg;
//    struct event* w_event = evtimer_new(work->w_base, cb_process, work);
work->w_event = evtimer_new(work->w_base, cb_process, work);

struct timeval  tVal;
tVal.tv_sec = 0;
tVal.tv_usec = 0;
//    evtimer_add(w_event, &tVal);
evtimer_add(work->w_event, &tVal);
}

static void cb_process(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg)
{
printf(“Process!!n”);
wctx* work = (wctx*)arg;
//    struct event* w_event = evtimer_new(work->w_base, cb_process_detail, work);
evtimer_assign(work->w_event, work->w_base, cb_process_detail, work);

struct timeval  tVal;
tVal.tv_sec = 0;
tVal.tv_usec = 0;
//    evtimer_add(w_event, &tVal);
evtimer_add(work->w_event, &tVal);
}

static void cb_process_detail(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg)
{
printf(“Detail Process!!n”);
wctx* work = (wctx*)arg;
event_free(work->w_event);
}

소스 수정 후, 다시 valgrind 를 돌려보았다.

pchero@MyGalaxy:~/workspace/Study/Program/LibEvent/memory_leak$ echo “Hello” | valgrind –leak-check=full ./main
==2440== Memcheck, a memory error detector
==2440== Copyright (C) 2002-2012, and GNU GPL’d, by Julian Seward et al.
==2440== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==2440== Command: ./main
==2440==
Process!!
Detail Process!!
System terminate…
==2440==
==2440== HEAP SUMMARY:
==2440==     in use at exit: 0 bytes in 0 blocks
==2440==   total heap usage: 11 allocs, 11 frees, 1,720 bytes allocated
==2440==
==2440== All heap blocks were freed — no leaks are possible
==2440==
==2440== For counts of detected and suppressed errors, rerun with: -v
==2440== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

결과는 성공!

문제 해결의 포인트는 다음과 같았다.

1. event_new()/evtimer_new() 의 사용을 줄이는 것. 가능하면 event_assign()/evtimer_assign() 을 사용하도록 했다.
2. new() 가 있으면 free() 도 해 준다는 것.