With using terminal for a long time, PATH variable tends to be longer and longer due to duplicated path.
Here is simple sample script - with Perl - to resolve this.

# remove duplication at give PATH-format-string
unique_path() {
perl -w -e '
    my %path_hash;
    exit unless (defined $ARGV[0]);
    foreach $p (split (/\:/, $ARGV[0])) {
        unless (defined $path_hash{$p}) {
            $path_hash{$p} = 1;
            push @newpath, $p;
        }
    }
    print join ":", @newpath;
' $1
}
...(skip)...
PATH=$(unique_path "$PATH")
...(skip)

Done :-).

Most Android device is 32bit machine. So, many application assumes that host machine is 32bit system.
And in general, there is no difference developing Android-natvie-library between 64bit and 32bit build machine.

But, here is usual step for developing Android-native-library.
(1) Developing and verifying code at build machine.
(2) Porting to NDK build system.

Most developers turns on full-warning-option at compile to detect bugs at early stage.
But, building and verifying codes assuming 32bit host machine at 64bit machine always issues type casting warning due to different type size.
Especially, between pointer and integer.

For example, many Android JAVA application uses int - jint - as a type to contain native pointer with assumption of 32bit-host-system.
Building this code at 64bit build system to verify code issues type casting warning, even if code itself is built perfectly at NDK build system.
And it is worse that this code doesn't work at 64bit Android host machine, even though it is not popular.

To reduce this warnings (for easy-verifying of library code at build machine), in my opinion, using long - jlong - instead of jint as a type for containing native pointer is better unless memory space is extremely critical.
And to make compiler be happy, using macro can be a good choice.
Here is example of macro for type-casting between pointer and integer - jlong.
(This sample works well without warning at 32bit/64bit build/host system).

#define ptr2jlong(v) ((jlong)((intptr_t)(v)))
#define jlong2ptr(v) ((void*)((intptr_t)(v)))

This is just simple example for portability issues.
Making portable code is always very difficult...

상당히 유명한 게임이라고 하기에, PC버젼으로 나온 1편을 플레이 해봤다. 사실 집에 PC가 워낙 오래된 것이라 (이제 만으로 7년정도 된거 같군...-_-;) 약간만 사양이 높아도 돌리지도 못한다...
일단 일러스트를 보면 왠지모르게 굉장히 익숙한 느낌! 바로 랑그릿사의 우루시하라 사토시! 그가 일러스트를 맡았다고 한다.
뭐 그림이야기는 그렇고... 게임은...
스토리... 괜찮고, 일러스트... 당연히 괜찮고, 완성도... 이 정도면 뭐...
그런데... 문제는... encounter시 전투에 시간이 너무 오래 걸린다는 점... 특히 마법은 effect때문에.. 너무 많은 시간을 소모해서 집중력을 확~~ 떨어뜨려 버린다.
그래서... 한번 clear하고 나면 다시 하고 싶은 생각은 별로 들지 않는다.
또, 마법과 물리 공격간에 밸런스가 약간 무너져서... 마법이 없이는 아무것도 할 수 없는 것도 약간은 아쉬움이라고 할까...
(물약으로 버티는 전사파티의 로망은 불가능하다...-_-;)
그럼에도 불구하고, 각 캐릭터의 개성이 확실하고, 기타 요소들이 괜찮아서 상당히 잘 만든 게임임에는 틀림없는 것 같다.
그렇지만... 역시 훼자리안 던전의 잔인함은.. 짜증.. 지대루다..-_-;

'Essay > Review' 카테고리의 다른 글

[Review][Game] 총망라...  (0) 2011.11.23
[Review] 삼국군영전5  (0) 2011.11.23
[Review] Extreme Programming Explained 2/E  (0) 2011.08.05
[Review] Kingdom Under Fire - Gold Edition  (1) 2011.08.05
[Review] Numb3rs (넘버즈)  (0) 2011.07.06

There is function for sleep in kernel - ex. msleep(). And schedule_timeout() is used in those.
And, schedule_timeout() calculates time for expiration based on current jiffies.
But some functions disable local irq or irq for a while in it.
For example, printk does this - disabling local irq.
But, jiffies is updated based on local timer irq (In case of SMP, one defined core - usually cpu0 - is used.)
So, disabling local irq - for timer core - may prevent system from updating jiffies.
At this moment, calling schedule_timeout() leads to set timer which expiring time is earlier than it should be because jiffies are behind of real time.
So, for example, msleep(100) may wake up after 50ms at this scenario.
This is very dangerous.
But, actually, lots of code uses jiffies directly in kernel.
So, I'm not sure that all those codes are safe in case that jiffies is behind.
Anyway, here is my sample fix for this potential issue of schedule_timeout().
I couldn't find any fix regarding this issue even in kernel-3.0.
So, I'm not sure I missed something.
But, as for me, this is definitely issue to consider when variable jiffies is directly used.
I hope that my sample fix regarding schedule_timeout is helpful for others.
(In my opinion, fundamentally, all codes that uses jiffies directly should be re-examined whether it is really safe or not in case that jiffies is behind.)

diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index 6811f4b..6c89958 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -290,6 +290,8 @@ extern unsigned long preset_lpj;

 #endif

+extern unsigned long exact_jiffies(void);
+
 /*
  * Convert various time units to each other:
  */
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 56f87fa..37e7bbf 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -99,6 +99,32 @@ static ktime_t tick_init_jiffy_update(void)
        return period;
 }

+/**
+ * exact_jiffies - return real jiffies value
+ *
+ * You can't sure that value from %jiffies varaible is real current time.
+ * Jiffies may not be updated for a while due to several reasones.
+ * So, to get exact value, current ktime and %last_jiffies_update should be used
+ */
+unsigned long exact_jiffies(void)
+{
+       unsigned long exact = jiffies;
+       if (tick_period.tv64
+           && last_jiffies_update.tv64) {
+               unsigned long seq, ticks;
+               ktime_t delta;
+               do {
+                       seq = read_seqbegin(&xtime_lock);
+                       delta = ktime_sub(ktime_get(), last_jiffies_update);
+                       ticks = ktime_divns(delta, ktime_to_ns(tick_period));
+                       /* +1 to compensate loss at division */
+                       exact = jiffies + ticks + 1;
+               } while (read_seqretry(&xtime_lock, seq));
+       }
+       return exact;
+}
+EXPORT_SYMBOL_GPL(exact_jiffies);
+
 /*
  * NOHZ - aka dynamic tick functionality
  */
diff --git a/kernel/timer.c b/kernel/timer.c
index c4714a6..628a714 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1304,7 +1304,6 @@ void run_local_timers(void)
  * without sampling the sequence number in xtime_lock.
  * jiffies is defined in the linker script...
  */
-
 void do_timer(unsigned long ticks)
 {
        jiffies_64 += ticks;
@@ -1457,7 +1456,7 @@ signed long __sched schedule_timeout(signed long timeout)
                }
        }

-       expire = timeout + jiffies;
+       expire = timeout + exact_jiffies();

        setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
        __mod_timer(&timer, expire, false, TIMER_NOT_PINNED);
@@ -1467,6 +1466,13 @@ signed long __sched schedule_timeout(signed long timeout)
        /* Remove the timer from the object tracker */
        destroy_timer_on_stack(&timer);

+       /*
+        * Reaching here means "timer interrupt is issued
+        *   and 'jiffies' is updated."
+        * So, 'jiffies' here is recently-updated-value
+        *   and 'jiffies' can be directly used
+        *   instead of using 'exact_jiffies()'
+        */
        timeout = expire - jiffies;

  out:

done.

XP자체는 이미 상당히 알려진 방법론이며, 모든 방법론이 그러하듯이 좋은 말들과 장미빛 미래를 제시한다.
때문에, 책을 읽을때, 이런 미사여구들은 필터링 할 필요가 있다.

내가 이해한 관점에서 보면, XP의 실천적 방법론의 핵심은 '사람'과 '테스트'다.
나 역시 여기에 동의하긴 한다.
그렇지만, XP는 나의 견해보다 좀더 극단적인 감이 있다.
어떤 통계적인 근거를 제시할 수 없으니, 내가 맞다는 주장을 펼칠 수는 없지만, '조금 지나치다.'라는 느낌은 분명히 있다.

특히 pair programming부분은 동의하기 어렵다. 이건 철저하게 개인의 성향에 따라 다르다.
어떤 사람은 pair programming에서 더 나은 성과를 보일 수 있겠지만, 그렇지 않은 사람도 분명히 상당수 존재할 것이다.
일단 나 부터가 pair programming에 대한 거부감이 있다.
그래서 난, 이를 약간 완화시킨, 내 나름대로의 방법론을 제시하고 싶다.
"최소한 2인 1팀이 되어 움직이게 한다."

2인 1팀이 하나 혹은 다수의 work item을 공동책임하에 진행하는것... 개인적으로 이런 방식이 더 나아 보인다.
물론 이때, 2인이 소위 사수/부사수 의 관계를 의미하는게 아니다. 완전히 동등한 두 사람을 말한다.
사수/부사수의 방법론은 또 다른 분야이니까 일단 뒤로 하자.

음.. 적다 보니 왠지모르게 미숙한 글의 냄새가 폴폴 풍긴다...쩝..
일단 이쯤에서 접고... 생각나면 다시 업데이트 하자..

* update (2011/Aug/19)
왜 2인 1팀이어야 하는가?
* Pair programming의 효과를 얻을 수 있다. 서로가 서로를 보완하며, review할 수 있다.
* 서로가 서로의 backup이 되어 줄 수 있기 때문이다.
둘 중 누구 하나가 휴가를 가야 한다던가, 갑자기 쉬어야 하는 경우, 다른 한 사람이 그 사람의 빈자리를 채워줄 수 있다.
* 단점 : 전문 분야가 최소한 두곳 이상이 생기게 되므로 업무의 효율이란 측면에서 손실이 있을 수도 있겠으나, 이는 시간이 지나면 해결될 수 있는 문제라고 본다.

'Essay > Review' 카테고리의 다른 글

[Review][Game] 총망라...  (0) 2011.11.23
[Review] 삼국군영전5  (0) 2011.11.23
[Review][Game] Growlancer (그로우랜서1)  (0) 2011.08.23
[Review] Kingdom Under Fire - Gold Edition  (1) 2011.08.05
[Review] Numb3rs (넘버즈)  (0) 2011.07.06

음... 오랜만에 게임 하나를 엔딩을 봤다.
사실 옛날에 엔딩을 봤던 게임이긴 한데, 최근에 다시 잡고 해 봤다는...
근데 상당히 재미있었다.
바로 Kingdom Under Fire(KUF).
일반적인 RTS게임에 RPG요소를 추가해서, Hero개념을 추가했다.
Warcraft3보다도 먼저 RTS에 Hero의 개념을 추가했다는...
순수 국산 이기도 하고...

물론, 고질적인 소프트웨어 불법 복제 때문에 안타깝지만 빛을 잃긴 했다...-_-;
여튼... 다시 해봐도 수작임은 분명하다.

그러고 보니 예전에 온게임넷에서 리그도 했었지 아마...
결승이... 전상욱 vs. 강xx 였던걸로 기억하는데 마지막에 건물이 먼저 깨어지느냐 히어로가 먼저 나오느냐의 시간싸움에서 '리히터 로젠하임'의 등장으로 결국 전상욱이 우승했던 기억이 난당...
정말 재미있었던 경기였었고, 그 덕분에 KUF를 아직도 좋아하고 있는지도 모르겠당...
여튼... 추천할 수 있는 작품...

'Essay > Review' 카테고리의 다른 글

[Review][Game] 총망라...  (0) 2011.11.23
[Review] 삼국군영전5  (0) 2011.11.23
[Review][Game] Growlancer (그로우랜서1)  (0) 2011.08.23
[Review] Extreme Programming Explained 2/E  (0) 2011.08.05
[Review] Numb3rs (넘버즈)  (0) 2011.07.06

In C, func() and func(void) have different function signature.
(But, in C++, these two are same.)

'func()' means 'this function can have any number of arguments (0 ~ infinite)'.
But, 'func(void)' means 'this function doesn't have argument.'
See following example.

#ifdef CASE1
void func(void); /* (1) */
#else
void func();     /* (2) */
#endif

void
func(int i) {
        ; /* do something */
}

If 'CASE1' is defined, compiling this file complains error like "error: conflicting types for 'func'".
But, 'CASE1' is not defined, this is well-compiled.
Now, you can clearly understand difference.

So, using 'func(void)' is better for readibility if 'func' really doesn't have any arguement, instead of just 'func()'.

*** One more. ***
In C, 'extern' for function is default visibility.
So, in function declaration, 'extern void func(void);' is exactly same with 'void func(void);'.
Therefore any of them is OK.
( [ omitting 'extern' for simplicity ] vs. [ using 'extern' to increase readability ] )
But, default visibility of function depends on compiler.
For portability reason, using macro is usually better instead of using explicit directive - especially at shared library header.
(Ex. 'EXTERN void func(void)')

넘버즈 전 시즌(1~6)을 정주행 했다. 음~ 뭐랄까... 볼만은 했으나, 강추까지는 아닌...
수학천재인 동생(찰리 앱스)과, FBI인 형(돈 앱스) 이렇게 두 사람이 이야기의 중심이 되는데... 동생이 수학을 이용해서 FBI의 수사를 돕는다는 내용이다.
뭐, 사실 모든 드라마가 그러하듯 현실성이 떨어지긴 하지만 (아무리 천재라곤 하지만 그 짧은 시간에 정의하기도 힘든 조건들을 가지고 수학적인 답을 얻어내는건... 도저히 이해할 수 없다...-_-; ), 어쨌든 아무 생각없이 보고 있으면, 그냥 꽤 괜찮은 수사물 정도로 볼 수도 있겠다.
후반 시즌으로 갈수록 시청률 저하때문에 고생했다고 하지만 (당연한건가?), 개인적으로는 전반부보다 후반부가 더 나았다.
단순한 수사물이였던 전반부에 비해서, 후반부에는 인간으로서 가질 수 있는 여러가지 고뇌들과 삶의 철학적인 내용이 묻어 나온다.

등장인물들의 일관성이 부족하고 - 왜 나왔는지 의미없이 잠깐씩 나왔다가 더 이상 등장하지 않는 인물들 - 큰 흐름에서 보았을때의 유기성은 좀 떨어지는 것 같으나, 등장 인물의 캐릭터 설정이 상당히 괜찮았던것 같다.
특히... 물리학 교수이자 찰리 앱스의 스승인 래리 플레인하르 교수의 존재감이란...^^;

이런 옴니버스식 드라마의 특징이라고 할 수도 있겠지만 전체적인 스토리의 깊이가 없어서 어느 정도 지나면 슬슬 지겨워 진다.
대신 소재가 무한정하니까, 시리즈를 길게 가져갈 수 있다는 장점이 있겠지만...

여튼 전체적으로 "볼만하다"라는 평을 하고 싶다.

'Essay > Review' 카테고리의 다른 글

[Review][Game] 총망라...  (0) 2011.11.23
[Review] 삼국군영전5  (0) 2011.11.23
[Review][Game] Growlancer (그로우랜서1)  (0) 2011.08.23
[Review] Extreme Programming Explained 2/E  (0) 2011.08.05
[Review] Kingdom Under Fire - Gold Edition  (1) 2011.08.05

GNU Global(henceforth Global) is good tagging tool.
In Global, user can add file or directory list to skip during parsing in the configuration file (~/.globalrc by default).

[ Customization 1 ]
But, in case of monster-like-huge-system, this file list becomes too big and complex.
So, one of my option to resolve this issue is "Using regular expression(henceforth regex.) directly in the configuration file."

To do this, source code of Global should be modified, definitely.
Following source code diff. is based on GNU Global 5.9.7

diff --git a/libutil/find.c b/libutil/find.c
index aa12e81..a49bcdf 100644
--- a/libutil/find.c
+++ b/libutil/find.c
@@ -263,9 +263,18 @@ prepare_skip(void)
                char *skipf = p;
                if ((p = locatestring(p, ",", MATCH_FIRST)) != NULL)
                        *p++ = 0;
+               /*
+                * [ Modification For My Private Usage! ]
+                * string starts with '/' is treated as regular expression.
+                * (Not file name!)
+                */
                if (*skipf == '/') {
-                       list_count++;
-                       strbuf_puts0(list, skipf);
+                       reg_count++;
+                       /* put it as it is as regular expression! */
+                       for (q = skipf + 1; *q; q++)
+                               strbuf_putc(reg, *q);
+                       if (p)
+                               strbuf_putc(reg, '|');
                } else {
                        reg_count++;
                        strbuf_putc(reg, '/');
@@ -288,6 +297,8 @@ prepare_skip(void)
                /*
                 * compile regular expression.
                 */
+               printf("********* skip regular expression ***********\n%s\n"
+                      ,strbuf_value(reg));
                skip = &skip_area;
                retval = regcomp(skip, strbuf_value(reg), flags);
                if (retval != 0)

Global keeps its skip list with following form.

(/<path0>|/<path1> ...)

And characters that can be used as regex. is replaced with leading escape character '\'.
So, all characters are treated as character itself and don't have meta meaning during regex. compilation.
To use regex. directly, modifying this code area is required and above diff. is for this.
Another thing to know to use regex. directly is that file path that is used in Global for parsing always starts with './'

Original Global supports absolute path.
But, in my case, it was almost useless.
So, instead of using absolute path, I modified it to use this for regex. syntax.
That is, syntax for absolute path is used as the one for regex. of configuration file in modified Global.
(printf is for debugging configuration file. :-) )

Here is example at the modified version.
(Leading automatically-added-default-expression  is omitted.)

Standard case
-------------

[ Configuration ]
:skip=tags,project/bin/,/b[0-9]+\.txt$:

[ Regular expression string ]
(/tags$|/project/bin/)

=> absolute path is stored at other list - not in regex.

Customized case
---------------

[ Configuration ]
 :skip=tags,project/bin/,/b[0-9]+\.c:

[ Regular expression string ]
(/tags$|/project/bin/|b[0-9]+.txt$)

[ Customization 2 ]

There is no well-described official document about Global configuration file.
So, I'm not sure that following case is intentional or not.

In configuration file, default leading string of regex. is '/'.
That is, "skip=build/:" is transformed to "/build/" in regex.
Therefore, this matches not only "./build" but also "xxxxx/build/xxxxx".
But this always confused me.
So, let me introduce modification to overcome this.

--- a/libutil/find.c
+++ b/libutil/find.c
@@ -277,7 +277,10 @@ prepare_skip(void)
                                strbuf_putc(reg, '|');
                } else {
                        reg_count++;
-                       strbuf_putc(reg, '/');
+                       /*
+                        * all local files are started with './'
+                        */
+                       strbuf_puts(reg, "^\\./");
                        for (q = skipf; *q; q++) {
                                if (isregexchar(*q))
                                        strbuf_putc(reg, '\\');

This means, "all file path is relative path from gtags' root."
For me, this is much better and clearer than original version.

Enjoy!

'Tools' 카테고리의 다른 글

[ Emacs ] key-bindings.... (my environment)  (0) 2012.03.23
Interesting rule of GNU make.  (0) 2012.03.23
[Tools] 'Tab' means 'Command' in Make.  (0) 2011.01.26
[Emacs] use Semantic with global...  (0) 2010.06.29
[Tool] gnumake...  (0) 2010.02.19

To use sysfs, enable kernel config : CONFIG_GPIO_SYSFS
Core files related with this : gpiolib.c at Kernel
sysfs nodes can be found at /sys/class/gpio

[ Prerequisite ]
writing value to '/sys/class/gpio/export' uses 'gpio_request()' function at gpiolib in kernel.
So, if given gpio is already requested by other owner, exporting is failed.
Therefore, gpio should not be owned by others in kernel to control gpio at user space.

[ How to use at user space ]
Assumption : current working directory is '/sys/class/gpio'

#> echo [gpio num] > export
=> export give gpio to sysfsgpioN link is newly created if gpio number is valid one.

#> cd gpioN
=> Then, several nodes (active_lowdirectionvalue etc) can be found.
Writing or reading following nodes, is one of useful way to debug/control gpio at user space.
(attribute functions for each node are defined at gpiolib.c)

[ Detail Example ]

* at /sys/class/gpio
export, unexport : gpio number
#> echo 86 > export
#> echo 86 > unexport

* at /sys/class/gpio/gpioN
direction : in, out, low, high
value : 0, 1
edge : none, rising, falling, both
active_low : 0, 1
#> echo in > direction
#> echo 1 > value
#> echo both > edge

< See gpio.txt of Kernel document for details about each sysfs node. >

+ Recent posts