20140714 (ARM Interrupt로 LED 켜기)

101일차







------------------

ARM Interrupt

------------------




------- 내부 Reg





------- 외부 Reg












------- Interrupt 함수

Interrupt 함수는 실행 속도와 처리 속도가 빨라야 하므로

변수 할당과 소스코드가 적어야 한다.



컴파일러마다 특징이 있는데

우선 컴파일러는 3가지가 있다

- IAR (Atmel 본사)

- Kei (다른 회사)

- gcc (gnu)


--- IAR 컴파일러의 특징

함수를 호출할 때 인자 4개 까지는 Reg에 저장하고

5번째것은 Stack에 저장하므로

메모리도 아끼고 Reg에 넣으므로 속도도 빠르다.


따라서 실제 성능을 최대로 뽑으려면 IAR을 사용해야 한다.







------- Reg

PIOA_IMR은 인터럽트 on/off 여부


PIOA_ISR은 인터럽트가 걸렸는지 여부

ISR은 한 번 읽으면 



인터럽트가 걸리면

한가지 함수만 사용하는데

그 함수 안에서 어떤 핀이 왔는지

프로그래밍적으로 구현해야 한다.









------- 예제 소스


- irq.c





- main.c







설정

트랙백

댓글

20140708 (ARM DBGU UART 통신)

97일차







-------------------

ARM DBGU 통신

-------------------




------- DBGU 통신


DBGU는 UART 로 통신하고 이것을 통하여 PC와 통신을 해보자.


먼저 arm보드에 uart 선을 꽂는데 아래 그림을 참고하여 꽂았다.



RS232 시리얼 포트가 컴퓨터에 없으므로 USB로 변환해주는 회로에 ARM과 연결하였다.






------- DBGU 통신 초기화


아래 차례로 초기화 소스를 작성한다.


1. I/O Lines

2. Power Management

3. Interrupt Source

4. UART Operations

5. 나머지 셋팅.









2번 과정을 주석 처리하였는데 그 이유는 아래 그림처럼


SYSC에 속해 있고,




밑에 그림에 1번이 SYSC이다.









클럭을 발생시키는 Reg를 살펴보니 1번과 0번은 만질수 없다.

항상 활성화되어 있다.

그래서 생략.






5번이 4.2.1 번보다 먼저 쓴 이유는 TX, RX를 켜기전에 설정해야 하기 때문에

먼저 선언하였다.



오늘은 여기까지...




설정

트랙백

댓글

20140707 (ARM LCD)

96일차











--------------

ARM LCD

--------------



------- LCD

LCD를 사용해 보는데 이전과 마찬가지로

전에 사용하던 소스를 들고와 다른 것 몇 가지만 수정한다.


--- 소스


- lcd.h





- lcd.c




- main.c




- makefile






lcd.c에서 PIO_OWER이란 reg를 썼는데

PIO_OSDR reg를 사용하기 위해서는 PIO_OWSR의 초기값이 읽기전용이라

PIO_OWSR이 읽기/쓰기 모드가 되어야 한다.

PIO_OWER를 set 시키면 PIO_OWSR이 읽기/쓰기 모드가 된다.


PIO_OSDR 은 atmega에서 Reg에 값을 넣는 방식처럼 사용할 수 있는 reg이다.









설정

트랙백

댓글

20140704 (ARM 회로도, Register 사용법)

95일차







----------

ARM

----------





------- 회로도
















------- Register 사용법

이전에는 장비에 대한 Reg를 사용하려면 주소를 찾아서 정의해 주었는데

이제는 제작사에서 만들어 놓은 정의를 사용한다.















이런식으로 사용한다.



typedef struct _node

{

...

struct _node * next;

}Node;


Node->next = 0;



이렇게 사용하는데

만약 Node의 주소를 알고 있다면



((Node *)100)->next = 0;



이렇게 사용할 수 있다.

그래서 위의 그림과 같이 된다.















설정

트랙백

댓글

20140703 (ARM ISP, USB Driver, LED 켜기)

94일차










--------

ARM

--------





------- ISP, USB Driver


ARM용 ISP 프로그램과 USB Driver를 다운 받는다.

atmel사 홈피에 들어가 아래 경로로 들어간다.


1.






2. ISP 관련 프로그램






3. ISP 관련 프로그램


이것 하나 다운 받고






4. 뭐시기 패키지인데...







5. 뭐시기 패키지. 아직 정체를 알 수 없음.






2가지를 받는다.










------- USB 드라이버 설치


설치시 설치 프로그램 경로를 

C:\Program Files\Atmel\sam-ba_2.12\drv

으로 삼바가 설치된 경로로 입력해 두면 설치가 된다.









------- LED를 켜라! 두번째 시간


main.c 맨 위에 Port 관련 Register들을 선언해 준다.








소스 작성 후 make를 걸어주고


arm 칩에 USB를 꽂아준다.


그리고 프로그램을 넣으면 끝.







설정

트랙백

댓글

20140702 (ARM Register Summary, LED 켜기)

93일차








-------

ARM

-------




------- 기본 준비


1. vi, 몇 가지 기본 설정함. 안해도 무방함.




1.tar


profile


1.tar 파일은 홈 디렉토리에 해제하고

profile 파일은 /etc/ 에 붙여넣고, 홈 디렉토리에 .profile 로 바꿔넣는다.





2. 어제 받은 arm-gcc 중에 4.1 버전을 설치한다.

그리고 

ARM_AT91SAM7S.zip

이 압축파일을 해제하고 그 해제한 폴더에 들어가 make 명령어를 걸어주는데

make 가 실패하면



cygwin 이 설치 된 폴더에 bin 경로를 추가해 주면 된다.


그리고 아까 압축해제한 폴더에 가서 다시 make가 걸리면 준비 끝.


그 폴더에 main.c 에 작성하면 된다.














------- AT91 SAM 7S 256 data sheet


--- Memory Map




AT91 SAM 7S 256 같은 경우 폰노이만 구조인데

상위 버전(9S)는 하바드 구조이다.




32 bit라 메모리 주소를 위와 같이 되어 있지만 실제 사용하지 않는 공간이 많다.

장치관련 Reg도 하부쪽에 분포되어 있다.


Remap?

- cstartup.s 소스 중에..












----- LED 켜기


우선 외부 port 제어하는 Reg를 찾는다.

AT91 SAM 7S 256은 32개의 PORT를 갖고 있다.





--- 관련 Reg



- Pin을 켜는 Reg





- Pin을 끄는 Reg





ATMega와 다르게 on, off Reg가 따로 있다.

그래서 이전 값을 유지시키는 코드가 필요없고 영향을 끼치지 않는다.


예를 들어

ATMega)

PORTA = PORTA | 0x01;  //  다른 값에 영향을 주지 않기 위한 코드.


ARM)

PORTA = 0x01;  //  0bit 켜는 코드. 다른 값에는 영향을 주지 않는다.




또 다른점으로 AVR은 Register Summary 표가 있는데

ARM은 없다. 그래서 Reg 주소값을 알아야 하는데... Data sheet 를 살펴보니 이런 표가 있었다.

(제작사마다, 부서마다 Register Summary를 붙여주고, 안 붙여주고 제 각각이다.)




offset 이란 곳에 주소처럼 보이는데 offset은 어떤 기준이 되는 주소에서 떨어진 만큼을 알려준다.

그럼 그 기준이 되는 주소는 Memory Map 에 나와 있다.





0xFFFF F400이 기준 주소인 것이다.

예로

PIO_PER : 0xFFFF F400

PIO_PDR : 0xFFFF F404


이렇게 주소가 되는 것이다.











오늘 한 수업 중에 PC reg에 대해서...






설정

트랙백

댓글

20140701 (ARM Cygwin, arm-gcc)

92일차








--------

ARM

--------




------- 기본 프로그램 설치

먼저 ARM을 배우기 앞서 필요한 프로그램을 설치한다.


Cygwin 이란 프로그램과

arm-gcc 프로그램이 필요하다.



Cygwin 은 linux 명령어를 windows 에서도 동일한 명령어를 사용할 수 있게 해주는 프로그램.



------ Cygwin 다운 받는 사이트

https://cygwin.com/index.html



사이트에 접속해서 밑으로 조금만 스크롤 하면





위에 보이는 사진과 같은 곳에 빨강 네모 친 곳을 클릭해서 다운 받을 수 있다.








------ arm-gcc 다운 받은 사이트

http://www2.amontec.com/gnuarm/files.html



빨강 네모 친 것들을 받으면 된다.








------- Cygwin 설치

Linux 계열에서는 프로그램을 설치할 때에

설치시켜주는 파일만 받아서 그 파일을 실행하면

어떤 서버에 접속하여 최신버전을 받아오는 형식으로 설치한다고 한다.


그래서 Cygwin을 실행시키면 아래와 같이 다시 다운 받는듯한 과정을 거친다.


1.




2.




3. 설치 모드 선택이다.

첫번째 - 인터넷에서 받음

두번째 - 다운만 받고 설치는 안함

세번째 - 로컬 디렉토리에 받은 것 설치




4. 사용할 수 있는 유저 설정.




5. 저장 위치




6. 그냥 Direct Connection 선택.




7. 다운 받을 사이트를 선택하는 것인데

인터넷에 카이스트나 다음이 빠르다고 하던데

일본 서버나 다음은 비슷한것 같다.




8.




9. 개발할 것이기 때문에 다른 것은 사용하지 않는다.

그림에 devel에 오른쪽 default를 한 번 클릭하여 install로 변경후 다음.




10. 다음




11. 기다림.




12.




13.












------- AVR Data sheets

모델 명은 AT91 sam7s256 이다.

ATmel사 사이트에 들어가면 받을 수 있다.




다운로드















설정

트랙백

댓글

20140626 (select, 1:1 채팅)

89일차









--------------

select 함수

--------------



--- select


select 는 상태가 변경되는 파일 기술자들의 숫자를 기다린다.


#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>


int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);


n : 감시하려는 파일 기술자들의 최고 큰 숫자 + 1

readfds : 읽기 감시 구조체

writefds : 쓰기 감시 구조체

exceptfds : 에러 감시 구조체

timeout : 감시 대기 시간. NULL값 줄 시 감시 될 때까지 무한대기



리턴값

       성공시

파일 기술자 집합에  포함된  기술자들의  숫자를  반환,  어떠한  일이  일어나기  전에 타임아웃이  발생하면  0을  반환한다.


 실패시

-1 반환, errno 는 적당한 값으로 설정된다. 집합들과 timeout 은 정의가 안되며, 그래서 에러후 이것들의 내용에 의지할수 없다.









--- fd_set 구조체








--- timeval 구조체


구조체 내에 변수의 값 만큼 대기한다.


struct timeval
{
    long tv_sec; /* seconds */
    long tv_usec; /* microseconds */
}











--- FD_CLR


fdset 중 소켓 fd에 해당하는 비트를 0으로 한다.


#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>


FD_CLR(int fd, fd_set *set);


fd : 비트를 0으로 바꿀 파일 디스크립터

set : 목표로 하는 fd_set 구조체








--- FD_ZERO


fdset 의 모든 비트를 지운다.


#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>


FD_ZERO(fd_set *fdset);


fdset : 모든 비트를 0으로 set 시킬 fd_set 구조체








--- FD_SET


fdset 중 소켓 fd에 해당하는 비트를 1로 한다.


#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>


FD_SET(int fd, fd_set *fdset);


fd : 비트를 1로 바꿀 파일 디스크립터

fdset : 목표로 하는 fd_set 구조체









--- FD_ISSET


fdset 중 소켓 fd에 해당하는 비트가 세트되어 있으면 양수값인 fd를 리턴한다.


#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>


FD_ISSET(int fd, fd_set *fdset);


fd : 비트를 알아볼 파일 디스크립터

fdset : 알아볼 fd_set 구조체












--- select 함수를 이용한 server와 client 1:1 채팅 프로그램



client 소스






server 소스








결과

















--- server 에서 client 정보 보기


1:1 채팅을 하는데 client의 정보를 확인하기


우선 예전에 ip번호를 할당할 때

int inet_aton(const char *cp, struct in_addr *inp);

이 함수로 "192.168.***.***" 이 문자열을 "C0A8****"란 16진수로 바꾸었다.

이번엔 반대로 client에서 들어온 정보에서 16진수를 문자열로 바꾸어 보기로 한다.
char *inet_ntoa(struct in_addr in); 이 함수가 우리가 보기 좋은? IP 번호로 바꾸어 준다.



( in_addr 구조체 찾은 방법)

$grep -R "struct in_addr" /usr/include/linux/




이제 server 소스를 수정하기로 한다.






실행화면











이제 client의 port 번호도 추가로




실행화면





설정

트랙백

댓글

20140625 (메시지 큐 우선순위, 공유 메모리)

88일차






----------------------

메시지 큐 우선순위

----------------------



--- 메시지가 처리될 때 우선순위를 정할 수도 있다.


예제 소스)


26_3.c


      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <sys/types.h>
      4 #include <sys/ipc.h>
      5 #include <sys/msg.h>
      6
      7 #define SIZE 124
      8
      9 struct
     10 {
     11     long type;
     12     char data[SIZE];
     13 }msg_data;
     14
     15 int main()
     16 {
     17     int msqid;
     18     int data_len;
     19     char buffer[SIZE];
     20
     21     if((msqid = msgget((key_t)7878, IPC_CREAT |0666)) == -1)
     22     {
     23         perror("msgget failed");
     24         exit(1);
     25     }
     26
     27     while(1)
     28     {
     29         printf("input data => ");
     30         scanf("%s", buffer);
     31         fflush(stdin);
     32
     33         if(!strcmp(buffer, "quit"))
     34         {
     35             break;
     36         }
     37
     38
     39         printf("input priority -> ");
     40         scanf("%ld"&(msg_data.type));
     41         fflush(stdin);
     42         strcpy(msg_data.data, buffer);
     43
     44         if(msgsnd(msqid, &msg_data, strlen(msg_data.data), 0== -1)
     45         {
     46             perror("msgsnd failed");
     47             exit(1);
     48         }
     49     }
     50     return 0;
     51 }





26_4.c


      1 #include <stdio.h>
      2 #include <sys/types.h>
      3 #include <sys/ipc.h>
      4 #include <sys/msg.h>
      5 #include <errno.h>
      6
      7 #define SIZE 124
      8 #define PRIOR 10
      9
     10 struct
     11 {
     12     long type;
     13     char data[SIZE];
     14 }msg_data;
     15
     16 int main()
     17 {
     18     int msqid;
     19     int data_len;
     20
     21     if((msqid = msgget((key_t)7878, IPC_CREAT |0666)) == -1)
     22     {
     23         perror("msgget failed");
     24         exit(1);
     25     }
     26
     27     while(1)
     28     {
     29         if((data_len = msgrcv(msqid, &msg_data, SIZE, (-1*PRIOR), IPC_NOWAIT)) == -1)
     30         {
     31             if(errno == ENOMSG)
     32             {
     33                 printf("no messgae\n");
     34                 break;
     35             }
     36
     37             perror("msgrcv failed");
     38             break;
     39         }
     40
     41         msg_data.data[data_len] = 0;
     42         printf("data : %s [%ld]\n", msg_data.data, msg_data.type);
     43     }
     44
     45     if(msgctl(msqid, IPC_RMID, 0== -1)
     46     {
     47         perror("msgctl failed");
     48         exit(1);
     49     }
     50
     51     return 0;
     52 }
     53





실행화면


















-----------------

공유 메모리

-----------------



--- 공유 메모리

 공유 메모리란 여러 프로세스가 함께 이용할 수 있는 메모리를 말한다.

모든 프로세스 전역변수? 같은 역할이다.



공유메모리를 사용할 때에는


1. 생성

2. 첨부

3. 분리

4. 제거


과정을 거친다.


공유 메모리를 가져와서 바로 쓸 수 있는게 아니라

공유 메모리를 자신의 메모리인 마냥 첨부 시켜야 한다고 한다.

다 사용 후 분리를 시켜주고 제거하거나 한다.




--- shmget

공유 메모리 생성


#include <sys/ipc.h>

#include <sys/shm.h>


int shmget(key_t key, int size, int shmflg);


key : 시스템에서 식별하는 공유 메모리 번호

size : 공유 메모리 크기

shmflg : 동작 옵션

IPC_CREAT : key에 해당하는 공유 메모리가 존재하지 않으면 생성하는데 접근 권한도 함께

부여해야 한다. 만약 공유 메모리가 있으면 이 옵션은 무시.

IPC_EXCL : 공유 메모리가 있으면 실패로 -1을 반환. 이 값이 설정되지 않으면 기존 공유

메모리에 접근하여 식별자를 반환한다.



리턴값

성공시

공유 메모리 식별자


실패시

-1






--- shmat

공유 메모리를 호출 프로세스 메모리로 첨부

(공유 메모리는 자신의 메모리에 첨부해야만 자신의 메모리인 것처럼 사용 가능하다)


#include <sys/types.h>

#include <sys/shm.h>


void * shmat(int shmid, const void * shmaddr, int shmflg);


shmid : 공유 메모리 식별자

shmaddr : 공유 메모리 주소, 일반적으로 NULL

shmflg : 동작 옵션

SHM_RDONLY : 읽기 전용으로 사용

SHM_RND : shmaddr을 NULL



리턴값

성공시

공유 메모리 주소 포인터


실패시

(void *)-1






--- shmdt

공유 메모리를 호출 프로세스 메모리에서 분리한다.


#include <sys/types.h>

#include <sys/shm.h>


int shmdt(const void * shmaddr);


shmaddr : 삭제할 공유 메모리 주소



리턴값

성공시

0


실패시

-1





--- shmctl

공유 메모리 제어한다.


#include <sys/ipc.h>

#include <sys/shm.h>


int shmctl(int shmid, int cmd, struct shmid_ds * buf);


shmid : 공유 메모리 식별자

cmd : 제어 종류

IPC_STAT : 공유 메모리의 정보를 얻어 buf에 저장.

IPC_SET : 공유 메모리의 정보를 buf에 저장한 값으로 변경한다. 단, shm_perm과 shm_ctime멤버에

대한 정보만 변경할 수 있다.

IPC_RMID : 공유 메모리를 제거. 이 때 세 번째 인수 buf는 0으로 지정.

buf : 공유 메모리 정보에 대한 포인터

struct shmid_ds

{

struct ipc_perm    shm_perm;        // 접근 권한

int    shm_segsz;                        // 세그먼트 크기(바이트)

time_t    shm_atime;                     // 최종 접근 시간

time_t    shm_dtime;                     // 최종 제거 시간

time_t    shm_ctime;                     // 최종 변경 시간

unsigned short    shm_cpid;         // 생성 프로세스의 PID

unisgned short    shm_lpid;          // 최종적으로 동작한 프로세스의 PID

short    shm_nattch;                     // 현재 접근한 프로세스의 수

unsigned short    shm_npages;     // 세그먼트의 크기(페이지)

unsigned long *    shm_pages;     // 페이지 테이블 항목을 위한 필드

struct shm_desc *    attaches;      // 접근을 위한 기술자들

};



리턴값

성공시

0


실패시

-1






예제 소스)


26_5.c


      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <sys/types.h>
      4 #include <sys/ipc.h>
      5 #include <sys/shm.h>
      6 #include <signal.h>
      7
      8 #define SIZE 1024
      9
     10 void signalHandler(int signo);
     11 int shmid;
     12
     13 int main()
     14 {
     15     void *shmaddr;
     16
     17     if((shmid = shmget((key_t)7878, SIZE, IPC_CREAT | 0666)) == -1)
     18     {
     19         perror("shmid failed");
     20         exit(1);
     21     }
     22
     23     if((shmaddr = shmat(shmid, (void*)00)) == (void *) -1)
     24     {
     25         perror("shmat failed");
     26         exit(1);
     27     }
     28
     29     strcpy((char*)shmaddr, "Linux Programming");
     30
     31     if(shmdt(shmaddr) == -1)
     32     {
     33         perror("shmdt failed");
     34         exit(1);
     35     }
     36
     37     signal(SIGINT, signalHandler);
     38     pause();
     39
     40     return 0;
     41 }
     42
     43 void signalHandler(int signo)
     44 {
     45     if(shmctl(shmid, IPC_RMID, 0== -1)
     46     {
     47         perror("shmctl failed");
     48         exit(1);
     49     }
     50
     51     exit(0);
     52 }





26_6.c


      1 #include <stdio.h>
      2 #include <sys/types.h>
      3 #include <sys/ipc.h>
      4 #include <sys/shm.h>
      5 #include <signal.h>
      6
      7 #define SIZE 1024
      8
      9 int main()
     10 {
     11     int shmid;
     12     void *shmaddr;
     13     struct shmid_ds shm_stat;
     14
     15     if((shmid = shmget((key_t)7878, SIZE, IPC_CREAT | 0666)) == -1)
     16     {
     17         perror("shmid failed");
     18         exit(1);
     19     }
     20
     21     if((shmaddr = shmat(shmid, (void*)00)) == (void *) -1)
     22     {
     23         perror("shmat failed");
     24         exit(1);
     25     }
     26
     27     printf("data read from shared memory : %s\n", (char *)shmaddr);
     28
     29     if(shmctl(shmid, IPC_STAT, &shm_stat) == -1)
     30     {
     31         perror("shmctl failed");
     32         exit(1);
     33     }
     34
     35     if(shmdt(shmaddr) == -1)
     36     {
     37         perror("shmdt failed");
     38         exit(1);
     39     }
     40
     41     kill(shm_stat.shm_cpid, SIGINT);
     42
     43     return 0;
     44 }




실행화면












------------

세마포어

------------



--- 세마포어?

세마포어란 여러 프로세스들이 한정된 자원을 사용할 때,

한정된 수의 프로세스만 사용할 수 있게 해주는 방법이다.









--- semget

세마포어 집합을 생성.


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>


int semget(key_t key, int nsems, int semflg);


key : 세마포어 ID

nsems : 생성할 세마포어 방 갯수

semflg : 옵션

IPC_CREAT : key에 해당하는 세마포어 ID가 없으면 접근 권한과 함께 생성.

없으면 무시.

IPC_EXCL : 세마포어 ID가 있으면 실패로 -1, 이 값을 설정해 주지 않으면

기존 세마포어 ID에 접근하여 ID를 반환한다.



리턴값

성공시

세마포어 ID


실패시

-1





--- semctl

세마포어 제어


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>


int semctl(int semid, int semnum, int cmd, union semun arg);


semid : 세마포어 ID

semnum : 세마포어 내에 제어할 세마포어 방 번호

0 이면 첫 번째 세마포어

1 이면 두 번째 세마포어

2 이면 세 번째 세마포어를 지칭한다.

cmd : 제어

GETVAL 세마포어의 현재 값을 구한다.

GETPID 세마포어에 가장 최근에 접근했던 프로세스의 프로세스 ID를 구한다.

GETNCNT 세마포어 값이 증가하기를 기다리는 프로세스의 개수

GETZCNT 세마포어 값이 0 이 되기를 기다리는 프로세스의 개수

GETALL 세마포어 집합의 모든 세마포어 값을 구한다.

SETVAL 세마포어 값을 설정

SETALL 세마퍼어 집합의 모든 세마포어 값을 설정

IPC_STAT 세마포어의 정보를 구한다.

IPC_SET 세마포어의 소유권과 접근 허가를 설정

IPC_RMID 세마포어 집합을 삭제

arg : cmd에 따라 다른 옵션



리턴값

성공시

0 이상 양수


실패시

-1





--- semop

세마포어 연산


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>


int semop(int semid, struct sembuf * sops, unsigned nsops);

semid : 세마포어 ID
sops : 연산할 내용
struct sembuf
{
short sem_num;
short sem_op;
short sem_flg;
};
sem_flg
IPC_NOWAIT : 호출 즉시 실행하지 못할 경우 기다리지 않고 실패로 -1 리턴
IPC_UNDO : 프로세스가 종료되면 세마포어 설정을 원래 상태로 되돌린다.
예기치 못한 종료에 세마포어를 원상복귀 시키지 못할 경우라도 복귀해 주기
때문에 설정해 주는 것이 좋다.
nsops : 연산할 갯수
한 번 계산하면 1
두 번 계산하면 2
보통 1이겠지?


리턴값
성공시
0

실패시
-1







예제 소스)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <sys/types.h>
      4 #include <sys/ipc.h>
      5 #include <sys/sem.h>
      6
      7 void repeat(int semid);
      8 void p(int semid);
      9 void v(int semid);
     10
     11 main()
     12 {
     13     int semid, i;
     14     union semun {
     15        int val;
     16        struct semid_ds *buf;
     17        unsigned short int *array;
     18     } arg;
     19
     20     // 세마포어가 1개인 8877 키의 세마포어 집합 생성
     21     if((semid=semget((key_t)88771, IPC_CREAT|0666)) == -1) {
     22        perror("semget failed");
     23        exit(1);
     24     }
     25
     26     // 세마포어 값을 1로 설정
     27     arg.val = 1;
     28     if(semctl(semid, 0, SETVAL, arg) == -1) {
     29        perror("semctl failed");
     30        exit(1);
     31     }
     32
     33     // 3개의 자식 프로세스 생성
     34     for(i=0; i<3; i++) {
     35        if(!fork())
     36           repeat(semid);
     37     }
     38
     39     // 10초간 정지
     40     sleep(10);
     41
     42     // semid 세마포어 삭제
     43     if(semctl(semid, 0, IPC_RMID, arg) == -1) {
     44        perror("semctl failed");
     45        exit(1);
     46     }
     47     exit(0);
     48 }
     49
     50 void repeat(int semid)
     51 {
     52     // 난수 초기화하기
     53     srand((unsigned int)getpid());
     54     p(semid);
     55
     56     // getpid()는 현재 프로세스의 프로세스 ID를 반환
     57     printf("%d process is using tool\n", getpid());
     58
     59     // 난수를 5로 나눈 나머지 초 동안 정지
     60     sleep(rand()%5);
     61     printf("%d process is returning tool\n", getpid());
     62     v(semid);
     63
     64     exit(0);
     65 }
     66
     67 void p(int semid)
     68 {
     69     struct sembuf pbuf;
     70
     71     pbuf.sem_num = 0;
     72     pbuf.sem_op = -1;
     73
     74     // 프로세스 종료하면 세마포어 설정 원상 복귀
     75     pbuf.sem_flg = SEM_UNDO;
     76
     77     // 현재 세마포어 값인 semval 1 감소하기
     78     if(semop(semid, &pbuf, 1== -1) {
     79        perror("semop failed");
     80        exit(1);
     81     }
     82 }
     83
     84 void v(int semid)
     85 {
     86     struct sembuf vbuf;
     87     vbuf.sem_num = 0;
     88     vbuf.sem_op = 1;
     89     vbuf.sem_flg = SEM_UNDO;
     90     // 현재 세마포어 값인 semval 1 증가하기
     91     if(semop(semid, &vbuf, 1== -1) {
     92        perror("semop failed");
     93        exit(1);
     94     }
     95 }












------------

select 함수

------------



--- select

파일 디스크립터들의 읽기, 쓰기, 오류를 감시한다.


       #include <sys/time.h>

       #include <sys/types.h>

       #include <unistd.h>


       int  select(int  n,  fd_set  *readfds,  fd_set  *writefds,

       fd_set *exceptfds, struct timeval *timeout);


       FD_CLR(int fd, fd_set *set);

       FD_ISSET(int fd, fd_set *set);

       FD_SET(int fd, fd_set *set);

       FD_ZERO(fd_set *set);




fd_set



http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/system_programing/File/select

설정

트랙백

댓글

20140624 (레코드 잠금, 파이프 통신, 메시지 큐)

87일차




------------------

레코드 잠금

------------------



--- 파일을 이용해 프로세스간 통신


소스)

exe3.c

      1 #include <stdio.h>
      2 #include <unistd.h>
      3 #include <fcntl.h>
      4
      5 int main(int argc, char **argv)
      6 {
      7     int fd;
      8     struct flock filelock;
      9
     10     filelock.l_type = F_WRLCK;
     11     filelock.l_whence = SEEK_SET;
     12     filelock.l_start = 0;
     13     filelock.l_len = 0;
     14
     15     fd = open(argv[1], O_RDWR | O_CREAT, 0666);
     16
     17     if(fcntl(fd, F_SETLK, &filelock) == -1)
     18     {
     19         perror("fcntl failed");
     20         exit(1);
     21     }
     22
     23     printf("locked %s\n", argv[1]);
     24
     25     write(fd, "Hi Linux"9);
     26     sleep(10);
     27
     28     printf("unlocked %s\n", argv[1]);
     29
     30     exit(0);
     31
     32     return 0;
     33 }





exe4.c

      1 #include <stdio.h>
      2 #include <unistd.h>
      3 #include <fcntl.h>
      4
      5 #define SIZE 20
      6
      7 int main(int argc, char **argv)
      8 {
      9     int fd;
     10     struct flock filelock;
     11     char buffer[SIZE];
     12     int length;
     13
     14     filelock.l_type = F_RDLCK;
     15     filelock.l_whence = SEEK_SET;
     16     filelock.l_start = 0;
     17     filelock.l_len = 0;
     18
     19     fd = open(argv[1], O_RDWR);
     20
     21     if(fcntl(fd, F_SETLKW, &filelock) == -1)
     22     {
     23         perror("fcntl failed");
     24         exit(1);
     25     }
     26
     27     printf("locked %s\n", argv[1]);
     28
     29     length = read(fd, buffer, SIZE);
     30
     31     write(STDOUT_FILENO, buffer, length);
     32     printf("unlocked %s\n", argv[1]);
     33
     34     exit(0);
     35
     36     return 0;
     37 }






결과














------------------

파이프 통신

------------------



--- 파이프


어떤 통로를 통해 프로세스끼리 통신할 수 있다.









--- popen

파이프를 이용해 명령어를 실행한다.


#include <stdio.h>


FILE *popen(const char *command, const cahr *type);


command : 실행할 명령어

type : 통신 형태

"r" 파이프를 통해 읽음

"w" 파이프를 통해 씀



리턴값

성공시

파일 포인터


실패시

NULL



--- pclose

파이프를 닫는다.


#include <stdio.h>


int pclose(FILE *stream);


stream : 닫을 파이프의 파일 포인터



리턴값

성공시

종료 상태


실패시

-1





--- pipe

파이프를 생성한다.


#include <unistd.h>


int pipe(int filedes[2]);


filedes[0] : 파이프로부터 데이터를 읽을 때 사용하는 파일 식별자

filedes[1] : 파이프에 데이터를 쓸 때 사용하는 파일 식별자






예제 소스)

      1 #include <stdio.h>
      2 #include <unistd.h>
      3 #include <string.h>
      4 #include <sys/types.h>
      5 #include <sys/wait.h>
      6
      7 #define SIZE 256
      8
      9 int main()
     10 {
     11     int pipes1[2];
     12     int pipes2[2];
     13     int length;
     14     char read_buffer[SIZE];
     15     char write_buffer[SIZE];
     16
     17     if(pipe(pipes1) == -1 || pipe(pipes2) == -1)
     18     {
     19         perror("pipe failed");
     20         exit(1);
     21     }
     22
     23     if(fork())
     24     {
     25         close(pipes1[1]);
     26         close(pipes2[0]);
     27
     28         if((length = read(pipes1[0], read_buffer, SIZE)) == -1)
     18     {
     19         perror("pipe failed");
     20         exit(1);
     21     }
     22
     23     if(fork())
     24     {
     25         close(pipes1[1]);
     26         close(pipes2[0]);
     27
     28         if((length = read(pipes1[0], read_buffer, SIZE)) == -1)
     29         {
     30             perror("read failed");
     31             exit(1);
     32         }
     33
     34         write(STDOUT_FILENO, "receive message: ", strlen("receive message: "));
     35         write(STDOUT_FILENO, read_buffer, length);
     36
     37         sprintf(write_buffer, "Hi client!\n");
     38         write(pipes2[1], write_buffer, strlen(write_buffer));
     39
     40         wait(NULL);
     41     }
     42     else
     43     {
     44         close(pipes1[0]);
     45         close(pipes2[1]);
     46
     47         sprintf(write_buffer, "Hi server\n");
     48         write(pipes1[1], write_buffer, strlen(write_buffer));
     49
     50         if((length = read(pipes2[0], read_buffer, SIZE)) == -1)
     51         {
     52             perror("read failed");
     53             exit(1);
     54         }
     55
     56         write(STDOUT_FILENO, "receive message: ", strlen("receive message: "));
     57         write(STDOUT_FILENO, read_buffer, length);
     58     }
     59
     60     exit(0);
     61     return 0;
     62 }



결과











--- FIFO


파이프는 부모 자식 프로세스 간에만 통신이 가능하고 종료되면 사라져 사용하기에 문제가 있다.

이런 문제점을 해결한 통신 수단이 FIFO이다.

이름있는 파이프라고도 불리는 이놈은 부모 자식간만 아니라 파이프 이름만 알면

어떤 프로세스도 사용가능하고 삭제하지 않는한 영구적이다.




--- mkfifo

FIFO를 생성한다.


#include <sys/types.h>

#include <sys/stat.h>


int mkfifo(const char * pathname, mode_t mode);


pathname : 생성될 FIFO의 이름

mode : 생성될 FIFO의 접근 권한



리턴값

성공시

0


실패시

-1






예제 소스)

25_13.c

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <fcntl.h>
      4 #include <sys/types.h>
      5 #include <sys/stat.h>
      6
      7 #define SIZE 128
      8 #define FIFO "fifo"
      9
     10 int main(int argc, char **argv)
     11 {
     12     int fd;
     13     char buffer[SIZE];
     14
     15     if(mkfifo(FIFO, 0666== -1)
     16     {
     17         perror("mkdifo failed");
     18         exit(1);
     19     }
     20
     21     if((fd = open(FIFO, O_RDWR)) == -1)
     22     {
     23         perror("open failed");
     24         exit(1);
     25     }
     26
     27     while(1)
     28     {
     29         if(read(fd, buffer, SIZE) == -1)
     30         {
     31             perror("read failed");
     32             exit(1);
     33         }
     34
     35         if(!strcmp(buffer, "quit"))
     36         {
     37             exit(0);
     38         }
     39
     40         printf("receive messgae: %s\n", buffer);
     41     }
     42
     43     return 0;
     44 }




25_14.c

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <fcntl.h>
      4 #include <sys/types.h>
      5 #include <sys/stat.h>
      6
      7 #define SIZE 128
      8 #define FIFO "fifo"
      9
     10 int main(int argc, char ** argv)
     11 {
     12     int fd;
     13     int i;
     14     char buffer[SIZE];
     15
     16     if((fd = open(FIFO, O_WRONLY)) == -1)
     17     {
     18         perror("open failed");
     19         exit(1);
     20     }
     21
     22     for(i = 1; i < argc; ++i)
     23     {
     24         strcpy(buffer, argv[i]);
     25
     26         if(write(fd, buffer, SIZE) == -1)
     27         {
     28             perror("write failed");
     29             exit(1);
     30         }
     31     }
     32
     33     return 0;
     34 }


결과



그런데 결과 그림에서는 잘 나온것 처럼 보이지만

사실 생성 권한? 이 없다는 오류가 났었는데 작업하던 디렉토리가

윈도우쪽 폴더라 에러가 났었다.












-------------

메시지 큐

-------------



--- msgget

메시지 큐를 생성한다.


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>


int msgget(key_t key, int msgflg);


key : 시스템에서 식별하는 메시지 큐 번호

msgflg : 동작 옵션

IPC_CREAT : key에 해당하는 메시지 큐가 없으면 큐를 새로 생성하는데,

이 때 접근 권한도 함께 부여해야 한다. 그러나 큐가 없으면 이 옵션은 무시한다.

큐가 있다면 식별자를 리턴값으로 준다.

IPC_EXCL : 메시지 큐가 있으면 실패라는 의미로 -1을 반환한다. 이 값이 설정되지 않으면

기존 메시지 큐에 접근해 식별자를 리턴한다.


리턴값

성공시

메시지 큐 식별자


실패시

-1




--- msgsnd

메시지 큐에 메시지를 전송한다.


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>


int msgsnd(int msqid, struct msgbuf * msgp, size_t msgsz, int msgflg);


msqid: 메시지 큐 식별자

msgp : 전송할 메시지

mssbuf 라고 기본적인 데이터형

struct msgbuf

{

long mtype;

char mtext[1];

};

크기가 매우 작지만 사용자 임의로 새로 만들수 있다

struct 데이터명

{

long type; // 첫 변수만 항상 long 형으로 지켜줘야한다.

아무타입...

};

msgsz : 메시지 크기

msgflg : 동작 옵션

IPC_NOWAIT : 메시지 큐가 가득 차 있어 메시지를 더 이상 저장할 수없을 경우에 실패로 -1 반환한다.

  이 값을 설정하지 않으면 메시지 큐가 메시지를 저장할 수 있을 때까지 기다린다.


리턴값

성공시

0


실패시

-1





--- msgrcv

메시지 큐에 있는 메시지를 수신한다.


#include <sys/types.h>

#include <sys/ipc.h>

#include <msg.h>


ssize_t msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg);


msqid : 메시지 큐 식별자

msgp : 메시지 수신할 곳

msgsz : 수신 가능한 메시지 크기

msgtyp : 수신할 메시지 선택 조건

0 : 메시지 큐에서 첫 번째 메시지를 수신한다.

양수 : 이 값과 메시지의 메시지 형식(mtype)이 일치하는 메시지를 수신한다.

음수 : 이 값의 절대값과 같거나 작은 메시지 형식을 갖는 메시지 중에서 가장 작은 메시지

형식을 갖는 메시지를 수신한다. 예를 들어, 세 개의 메시지 형식이 각각 5, 1, 9라 하자.

msgtyp가 -10이라면 -10의 절대값인 10보다 작거나 같은 메시지 형식을 갖는 메시지는

모두 해당된다. 이 중 가장 작은 1을 메시지 형식으로 갖고 있는 메시지를 수신한다.

msgflg : 동작 옵션

IPC_NOWAIT : 메시지 큐에 메시지가 없으면 실패로 -1을 반환한다. 이 값을 설정하지 않으면

  메시지가 메시지 큐에 도착할 때까지 기다린다.

MSG_NOERROR : 메시지 크기가 msgsz보다 클 때 초과되는 부분을 자른다. 이 값을 설정

하지 않으면 실패로 -1을 반환한다.



리턴값

성공시

수신한 메시지 크기


실패시

-1




--- msgctl

메시지 큐를 제어한다.


#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>


int msgctl(int msqid, int cmd, struct msqid_ds *buf);


msqid : 메시지 큐 식별자

cmd : 제어 종류

buf : 메시지 큐 정보에 대한 포인터



리턴값

성공시

0


실패시

-1







예제 소스)


msg1.c


      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <sys/types.h>
      4 #include <sys/ipc.h>
      5 #include <sys/msg.h>
      6 #include <signal.h>
      7
      8 #define SIZE 124
      9
     10 void signalHandler(int signo);
     11
     12 //메시지를 저장하는 데이터형으로 첫 번재 멤버는 메시지 형식이어야 함
     13 struct{
     14     long type;
     15     char data[SIZE];
     16 }msg_data={1"Linux C Programming"};
     17
     18 int msqid;
     19
     20 int main()
     21 {
     22     //1234 키를 갖는 메시지 큐를 생성하고 메시지 큐 식별자인 정수값을 반환
     23     //만약 1234 키의 메시지 큐가 있으면 메시지 큐에 접근하여 식별자를 반환
     24     if(msqid=msgget((key_t)1234, IPC_CREAT|0666== -1)
     25     {
     26         perror("msgget failed");
     27         exit(1);
     28     }
     29
     30     //msg_data 메시지를 msqid 메시지 큐에 전송
     31     if(msgsnd(msqid, &msg_data, strlen(msg_data.data),0== -1)
     32     {
     33         perror("msgsnd failed");
     34         exit(1);
     35     }
     36
     37     //SIGINT 시그널을 받으면 signalHandler을 실행하도록 설정
     38     signal(SIGINT,signalHandler);
     39     pause();
     40
     41     return 0;
     42 }
     43
     44 void signalHandler(int signo)
     45 {
     46     //msqid 메시지 큐 삭제
     47     if(msgctl(msqid,IPC_RMID,0)== -1)
     48     {
     49         perror("msgctl failed");
     50         exit(1);
     51     }
     52
     53     exit(0);
     54 }







msg2.c


      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <sys/types.h>
      4 #include <sys/ipc.h>
      5 #include <sys/msg.h>
      6 #include <signal.h>
      7
      8 #define SIZE 124
      9
     10 struct
     11 {
     12     long type;
     13     char data[SIZE];
     14 }msg_data;
     15
     16 int main()
     17 {
     18     int msqid;
     19     struct msqid_ds msg_stat;
     20
     21     //1234 키의 메시지 큐가 있으면 접근해서 식별자 받음
     22     if(msqid=msgget((key_t)1234,IPC_CREAT|0666== -1)
     23     {
     24         perror("msgget failed");
     25         exit(1);
     26     }
     27
     28     //msqid 메시지 큐에서 메시지를 읽어 msg_data에 저장
     29     if(msgrcv(msqid, &msg_data, SIZE,0,0== -1)
     30     {
     31         perror("msgrcv failed");
     32         exit(1);
     33     }
     34
     35     printf("data read from message queue : %s\n",msg_data.data);
     36
     37     //msqid 메시지 큐 정보를 얻어 msg_stat에 저장
     38     if(msgctl(msqid, IPC_STAT, &msg_stat) == -1)
     39     {
     40         perror("msgctl failed");
     41         exit(1);
     42     }
     43
     44     //msg_stat.msg_lspid 프로세스에게 SIGINT 시그널을 보냄
     45     kill(msg_stat.msg_lspid,SIGINT);
     46
     47     exit(0);
     48
     49     return 0;
     50 }




실행








설정

트랙백

댓글