시스템콜(System call)과 작업 영역

|

대부분의 시스템은 작업 범위와 안정성을 위해 크게 두 가지의 작업 영역으로 나눕니다.

  • 커널 영역 (Kernel Space)
  • 사용자 영역 (User Space)


커널 영역 (Kernel Space)

커널 영역은 커널이 작업하는 영역으로 CPU 작업 스케줄이나 하드웨어를 제어하는 디바이스 드라이버와 메모리를 관리하는 기능 등을 수행합니다.

이러한 작업을 위해 CPU에서 제공하는 명령얻이 존재합니다. 그 중에는 `특수 명령어(Privileged Instruction)’도 존재합니다. 특수 명령어의 경우 오로지 커널에서만 사용 가능하며 일반 라이브러리에서는 호출할 수 없습니다.

커널은 가장 신뢰할 수 있는 프로그램들로만 구성되어져야 하며, 만약 커널에서 오류가 발생하면 그대로 시스템 종료로 이어집니다.


사용자 영역 (User Space)

사용자 영역은 일반 프로그램이 실행되는 영역으로 해당 프로그램만의 공간입니다. ‘샌드박스(Sand Box)’라고도 부릅니다. 사용자 영역에서는 직접 하드웨어 디바이스 또는 메모리를 제어할 수는 없습니다. 작업을 위해서는 ‘시스템콜(System call)’을 이용해 커널에 작업을 요청하고 커널의 도움을 받아 작업을 수행할 수 있습니다.


예제

예를 들어 ‘a = b + c’라는 문장을 수행하는 작업은 사용자 영역에서 수행되는 작업이지만, ‘char* buffer = (char*)malloc(100)’과 같은 메모리를 할당하거나 파일을 건드리는 작업 등은 커널의 도움을 받아야만 가능한 작업들입니다.


Operating System Trap

작업 영역의 변환은 일종의 소프트웨어 인터럽트라고 불리우는 Operation System Trap을 통해 이루어집니다. 어플리케이션의 요청과 작업에 필요한 데이터는 커널에 작업을 요청할 때, 사용자 영역에서 커널 영역으로 복사하여 전달합니다. (물론 반대의 경우도 마찬가지입니다.)

시스템 트랩이 발생할 경우, 어플리케이션에서 수행하던 모든 작업들이 중단되고 작업 권한이 커널로 넘어갑니다.

즉, 빈번한 시스템콜 호출은 전반적인 성능 하락을 가져옵니다.

콘솔창에 Colored Text 출력하기

|

Putty와 같은 터미널에서는 색상이 입혀진 텍스트를 화면에 출력할 수 있습니다. ANSI Color Code라고 하며, ANSI Escape Code의 기능 중 하나입니다. ANSI Escape Codesms 터미널에서 텍스트 포맷을 제어하기 위해 만든 코드이며, 현재 ISO/IEC-6429 표준으로 제정되어 있습니다.

대부분의 터미널에서는 이 기능을 지원하는데, Windows의 커맨드 창(Command Shell)에서는 이 기능을 지원하지 않는 것 같습니다.

ANSI Escape Code

Code Effect Note
0 Reset / Normal all attributes off
1 Intensity: Bold  
2 Intensity: Faint not widely supported
3 Italic: on not widely supported. Sometimes treated as inverse.
4 Underline: Single  
5 Blink: Slow less than 150 per minute
6 Blink: Rapid MS-DOS ANSI.SYS; 150 per minute or more
7 Image: Negative inverse or reverse; swap foreground and background
8 Conceal not widely supported
21 Underline: Double not widely supported
22 Intensity: Normal not bold and not faint
24 Underline: None  
25 Blink: off  
27 Image: Positive  
28 Reveal conceal off  

이 외에도 더 많은 ANSI Escape Code 들이 있지만, 이 중에서 텍스트의 색상을 결정하는 코드들은 30부터 39까지, 텍스트의 배경색은 40부터 49까지 존재합니다.


ANSI Color

Code Effect
30 set foreground color to black
31 set foreground color to red
32 set foreground color to green
33 set foreground color to yellow
34 set foreground color to blue
35 set foreground color to magenta (purple)
36 set foreground color to cyan
37 set foreground color to white
39 set foreground color to default (white)
40 set background color to black
41 set background color to red
42 set background color to green
43 set background color to yellow
44 set background color to blue
45 set background color to magenta (purple)
46 set background color to cyan
47 set background color to white
49 set background color to default (black)


소스 코드

위와 같은 ANSI Color 색상을 printf 함수나 cout 함수 등을 통해 쉽게 출력할 수 있도록 예제 코드는 다음과 같습니다.

Log.h

#ifndef LITOSERVICE_UTILS_LOG_H_
#define LITOSERVICE_UTILS_LOG_H_

class Log {
 public:
  static void v(const char* format, ...);
  static void d(const char* format, ...);
  static void i(const char* format, ...);
  static void w(const char* format, ...);
  static void e(const char* format, ...);

 private:
  Log() {}
  virtual ~Log() {}
};

#endif /* LITOSERVICE_UTILS_LOG_H_ */


Log.cc

#include <Log.h>
#include <cstdio>
#include <stdarg.h>

#ifdef __ANDROID__
#include <android/log.h>
#else
#include <stdarg.h>
#endif

#ifdef __ANDROID__
#define PLOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, gProseLogTag, __VA_ARGS__)
#define PLOGD(...) __android_log_print(ANDROID_LOG_DEBUG, gProseLogTag, __VA_ARGS__)
#define PLOGI(...) __android_log_print(ANDROID_LOG_INFO, gProseLogTag,__VA_ARGS__)
#define PLOGW(...) __android_log_print(ANDROID_LOG_WARN, gProseLogTag,__VA_ARGS__)
#define PLOGE(...) __android_log_print(ANDROID_LOG_ERROR, gProseLogTag, __VA_ARGS__)
#define PLOGF(...) __android_log_print(ANDROID_FATAL_ERROR, gProseLogTag,__VA_ARGS__)
#define PLOGS(...) __android_log_print(ANDROID_SILENT_ERROR, gProseLogTag,__VA_ARGS__)
#else
#define LOGV(...)
#define LOGD(...)
#define LOGI(...)
#define LOGW(...)
#define LOGE(...)
#define LOGF(...)
#define LOGS(...)
#endif

void Log::v(const char* format, ...) {
  char message[1024] = { 0, };

  va_list lpStart;
  va_start(lpStart, format);
  vsprintf(message, format, lpStart);
  va_end(lpStart);

  printf(FCYN("[%s] %s\n"), gLitoServiceTag, message);
  LOGV("%s", message);
}

void Log::d(const char* format, ...) {
  char message[1024] = { 0, };

  va_list lpStart;
  va_start(lpStart, format);
  vsprintf(message, format, lpStart);
  va_end(lpStart);

  printf(FGRN("[%s] %s\n"), gLitoServiceTag, message);
  LOGD("%s", message);
}

void Log::i(const char* format, ...) {
  char message[1024] = { 0, };

  va_list lpStart;
  va_start(lpStart, format);
  vsprintf(message, format, lpStart);
  va_end(lpStart);

  printf(FYEL("[%s] %s\n"), gLitoServiceTag, message);
  LOGI("%s", message);
}

void Log::w(const char* format, ...) {
  char message[1024] = { 0, };

  va_list lpStart;
  va_start(lpStart, format);
  vsprintf(message, format, lpStart);
  va_end(lpStart);

  printf(FMAG("[%s] %s\n"), gLitoServiceTag, message);
  LOGW("%s", message);
}

void Log::e(const char* format, ...) {
  char message[1024] = { 0, };

  va_list lpStart;
  va_start(lpStart, format);
  vsprintf(message, format, lpStart);
  va_end(lpStart);

  printf(BOLD(FRED("[%s] %s\n")), gLitoServiceTag, message);
  LOGE("%s", message);
}

라즈베리파이 C++ 크로스 컴파일(Cross Compile) 환경 설정

|

라즈베리파이용 프로그램을 Windows PC에서 개발할 수 있도록 크로스 컴파일(Cross Compile) 환경을 설정하는 방법입니다.


툴체인(Toolchain) 다운로드 및 설치

먼저 Windows toolchain for Raspberry/PI을 다운로드 하고 설치를 합니다.

image -fullwidth


Eclipse 설치

Visual GDB 같은 상용 IDE도 존재하지만, 여기서는 무료로 사용할 수 있는 Eclipse를 활용하도록 하겠습니다.

Eclipse Download 사이트로 가서 Eclipse IDE for C/C++ Developers를 다운로드합니다.

그리고 환경 설정으로 가거나 새로운 프로젝트를 하나 만들어서 Cross GCC 설정을 해줍니다.

image

image

크로스 컴파일러 prefix를 arm-linux-gnueabihf-로 설정합니다.

이제 Hello, World 등의 간단한 코드를 실행해서 빌드가 잘되는지 확인하면 됩니다.


C++11 환경 설정

라즈베리파이용 툴체인도 C++11 이상을 지원합니다. 따라서 이왕 개발할거면 C++11 이상으로 개발하는 것이 좋을 것 같습니다.

image

Project > Properties > C/C++ Build / Settings > Tool Settings에서 [GCC C++ Compiler] 항목과 [GCC C Compiler] 항목에서 [Miscellaneous] 항목을 찾습니다. 그리고 [Other flags] 뒷 부분에 다음 옵션을 추가합니다.

-std=c++0x


위와 같이 설정하면 C++11 문법으로 빌드는 되지만, Eclipse IDE 상에서는 문법 오류로 표시됩니다. 아래의 설정을 추가로 해주시면 됩니다.

image

Project > Properties > C/C++ General > Preprocessor Include Paths, Macros etc에서 [Providers] 탭을 선택한 다음 [CDT GCC Built-in Compiler Settings MinGW] 항목을 선택합니다. 그리고 아래쪽에 있는 Flag 설정 칸에 다음 옵션을 추가해줍니다.

-std=c++0x


그 이후 C/C++ Index Rebuild 를 수행해주면 Eclipse IDE가 C++11 문법을 정상적으로 인식합니다.

image

라즈베리파이 호스팅 네임 변경

|

라즈베리파이의 호스팅 네임(Hosting Name)을 변경하는 방법입니다. 라즈베리파이의 디바이스 이름이 변경되며, 블루투스 등에서 기기를 검색할 때 뜨는 이름도 변경됩니다.


/etc/hostname

sudo nano /etc/hostname

기본 이름으로 raspberrypi가 입력되어 있을 텐데, 원하는 이름으로 변경합니다. 저 같은 경우는 snowdeer-raspberry로 변경했습니다.


/etc/hosts

DNS 매핑을 관리하는 파일입니다. 이 부분을 제대로 설정하지 않으면 종종 다음과 같은 오류 메세지를 볼 수 있습니다.

sudo: unable to resolve host snowdeer-raspberry

다음 명령어를 이용해서 `hosts’ 파일을 열어줍니다.

sudo nano /etc/hosts

127.0.0.1 raspberrypi로 되어 있는 부분을 127.0.0.1 snowdeer-raspberry로 변경하시면 됩니다.


raspi-config

더 편리한 방법은 raspi-config 프로그래을 이용하는 방법입니다. 여기를 참조하세요.

블루투스 라이브러리 설치

|

블루투스 라이브러리 설치

라즈베리파이에서 블루투스 모듈을 사용한 프로그램을 개발할 때 다음과 같은 라이브러리들을 설치해주어야 합니다.

sudo apt-get install build-essential libbluetooth-dev


SDP Server 활성화

그리고나서 SDP Server를 활성화해주어야 하는데, dbus-org.bluez.service 파일의 내용을 다음과 같이 편집해 주면 됩니다.

sudo nano /etc/systemd/system/dbus-org.bluez.service

nano를 이용해서 dbus-org.bluez.service 파일을 열고, 그 안에

ExecStart=/usr/lib/bluetooth/bluetoothd

부분을 찾아서 뒤에

ExecStart=/usr/lib/bluetooth/bluetoothd --compat

와 같이 --compat 옵션을 붙여줍니다.


.bashrc 편집

그 다음 현재 라즈베리파이의 홈 폴더의 .bashrc 파일을 열어서

nano /home/pi/.bashrc

다음과 같은 코드를 추가합니다.

sudo chmod 777 /var/run/sdp

그리고 라즈베리파이를 재시작 해주시면 됩니다.