Windows XP 에서의 장치관리자 : Device Driver에 관하여

Slides:



Advertisements
Similar presentations
1/37 한글에는 전문적인 문서 편집을 위한 고급 기능이 있다. 문서를 편리하게 수 정할 수 있도록 도와주는 찾기 / 찾아 바꾸기, 다른 위치로 이동할 수 있는 책 갈피와 하이퍼링크에 대해 알아보자. 그리고 자주 사용하는 서식을 미리 정 해 놓고 쓰는 스타일 활용법과 스타일이.
Advertisements

아이튠즈 계정 생성. 1. 인터넷을 통해 설치한 아이튠즈를 실행 한 후 그림의 순서대로 선택을 합니다. 1 2.
ISLab Flash Team Ch 9. Hardware Initialization. ISLab Flash Team Made By Povolon Ch 6. 초기화 및 정리 루틴 2 Contents 1.Plug and Play Architecture 2.The Role.
J-Stream part1 (Software streaming service) ▪ 팀명 : Jukdori ▪ 팀원 : 16 th 윤병호 (PL) 15 th 송인규 16 th 김영진.
키보드 보안 순천향대학교 정보보호학과 임강빈 교수.
기초C언어 제1주 실습 강의 소개, C언어 개요, Cygwin/Eclipse 사용 컴퓨터시뮬레이션학과 2016년 봄학기
Project #2-2. Pintos User Program
Linux/UNIX Programming
DB 프로그래밍 학기.
DB 프로그래밍 학기.
1. 개발 시스템 개요.
Ubuntu 실습 환경 만들기 컴퓨터공학부 김찬민.
컴퓨터프로그래밍 1주차실습자료 Visual Studio 2005 사용법 익히기.
<<< 시스템등록정보 “하드웨어-장치관리자” 설정 >>>
MCMS3000 네트워크 설정방법 [반도 HFCNMS 시스템 Set-up] 반도전자통신
Image & Video processing
Database Laboratory, Hong Ik University
Consumer PC & AIO PC DMI Refresh 방법 설명 (UEFI DMI Ver)
C 프로그래밍 소개 숙명여대 창병모 2011 가을.
Windows CE 시스템 개발 환경 구축.
제6장 FUSING.
1장. 이것이 C 언어다.. 1장. 이것이 C 언어다. 프로그래밍 언어 1-1 C 언어의 개론적 이야기 한글, 엑셀, 게임 등의 프로그램을 만들 때 사용하는 언어 ‘컴퓨터 프로그래머’라는 사람들이 제작 C 언어(C++ 포함)를 가장 많이 사용함.
CUDA Setting : Install & Compile
Linux/UNIX Programming
Minicom,tftp,nfs설정,vnc설정
FUSING.
Ch 14. System Thread.
Linux를 이용한 Embedded 장비 개발
UNIT 06 JTAG Debugger 로봇 SW 교육원 조용수.
임베디드 시스템 개론 크로스 플랫폼 설치 2일차 강의 자료 Embedded System Lab.
Embedded System Porting (2)
CHAPTER 02 OpenCV 개요 PART 01 영상 처리 개요 및 OpenCV 소개.
1. C++ 시작하기.
ServerGuide CD를 이용한 xSeries 설치가이드
Ch 13. Windows 관리 기구.
Outlook Addin 설치 방법 및 매뉴얼
Geek-OS Project 정영진
부트로더와 Self Programming
소프트웨어 분석과 설계 Struts2 & JBOSS 설치하기
WinCE Device Driver 실습 #3
WinCE Device Driver 실습 #2
Cross Compiler 설치.
DK-128 개발환경 설정 아이티즌 기술연구소 김태성 연구원
Linux/UNIX Programming
Ch 6. Initialization and Cleanup Routines
홀인원2.0 설치 메뉴얼.
IPython Notebook + Spark + TensorFlow on MacOS
임베디드 시스템 개론 임베디드 타겟 보드 포팅 및 H/W 제어 3일차 강의 자료 Embedded System Lab.
툴 설치 가이드 Formality SynopsysMentor.
HyperWorks Apps 설치 가이드.
Linux/UNIX Programming
1. 스크립트 작성 마법사 2. NSIS 스크립트 컴파일
7주차 실습 FPGA 보드 사용법.
PMIS 서버 설정 환경설정 작성자 : 배경환.
빌드 성공.
Outlook 손상된 PST 복구
DK-128 직렬통신 기초 아이티즌 기술연구소
Kernel, Ramdisk, JFFS2 Porting
( Windows Service Application Debugging )
제 6 강 Getting started.
OpenCV 설정 2.21 만든이 딩딩.
DK-128 개발환경 설정 아이티즌 기술연구소 김태성 연구원
DK-128 개발환경 설정 아이티즌 기술연구소
수동 설치시는 설치 방법 1. 두번에 설치 CD 속에 fscommand 폴더 밑에 Osstem 이라는 폴더를
Tensorboard in Windows
농구 로봇 따라해 보기.
1. 인터넷 보안 옵션 레지스트리 등록 Config Setup 클릭.
Installation Guide.
1. SNMP Setting IP 설정 NetAgent Mini 카드에 제공된 CD의 Netility 프로그램을 설치하여 프로그램을 실행시킨다. Netility 프로그램을 실행하면 네트워크에 있는 SNMP 카드를 찾게 됩니다. “Configure”를 선택하면 IP 설정.
Eclipse를 이용한 Embedded Linux 응용 프로그램 개발
Presentation transcript:

Windows XP 에서의 장치관리자 : Device Driver에 관하여 Sep 5, 2008. CHONBUK NATIONAL UNIVERSITY Prof. Woonchul Ham 2018-09-22

Device Driver 응용사례 : UsbBulk.sys Application Program 개요 장치관리자란? Device Driver 작업환경은? Driver 의 구조 Plug & Play Device Driver 응용사례 : UsbBulk.sys Application Program 2018-09-22

내 컴퓨터->속성-> 하드웨어->장치관리자 장치관리자란? 내 컴퓨터->속성-> 하드웨어->장치관리자 2018-09-22

장치관리자란? (USB) 이곳을 클릭 2018-09-22

장치관리자란? (USB) 2018-09-22

장치관리자란? (USB) 2018-09-22

장치관리자란? (USB) USBSTOR.SYS 파일을 이해하고 만들어 본다. 이러한 *.SYS 파일이 바로 Device Driver 이며, 이 동적라이브러리를 통하여 응용프로그램(*.exe) 이 OS 와의 대화를 통하여 하드웨어를 접근할 수 있게 되는 것이다. 2018-09-22

Hardware Abstraction layer(HAL) 장치드라이버란? (USB) Applications Win32 API User Mode Kernel Mode Other Kernel Mode Driver Operating System Kernel File System Drivers Hardware Abstraction layer(HAL) Hardware 2018-09-22

5. Device Driver 응용사례 : UsbBulk.sys 1. 장치관리자란? 2. Device Driver 작업환경은? 3. Driver 의 구조 4. Plug & Play 5. Device Driver 응용사례 : UsbBulk.sys 6. Application Program 2018-09-22

2. Windows Device Driver Tool kit 설치 1. Windbg 설치 2. Windows Device Driver Tool kit 설치 3. NULL Modem Cable 연결 4. Target Computer, Host Computer 2018-09-22

2. Device Driver 작업환경은? : Windbg 설치 먼저 두 대의 컴퓨간에 널 모뎀 케이블과 하이퍼터미널을 이용하여 통신여부를 파악한다. (buadrate, no hardware로 세팅하여 확인하며, 또한 파일 전송 여부가 잘되는 지도 확인 하면 좋을 듯) Target 컴퓨터의 OS 시스템이 설치된 하드디스크 (C:)  폴더에 있는 BOOT.INI 파일의 내용을 다음과 같이 수정한다. 물론 baudrate와 comport값을 적절하게 세팅하여야 한다. [boot loader] timeout=10 default=multi(0)disk(0)rdisk(0)partition(1)\WINNT [operating systems] multi(0)disk(0)rdisk(0)partition(1)\WINNT="Microsoft Windows 2000 Professional" /fastdetect /noguiboot multi(0)disk(0)rdisk(0)partition(1)\WINNT="MS Win 2000 Professional-Prof.Ham" /fastdetect /noguiboot /debug /debugport=com1 /baudrate=115200 2018-09-22

2. Device Driver 작업환경은? : Windbg 설치 Host Computer에 Windbg 6.0 버전을 설치한다 Target 컴퓨터에서 작성된 *.pdb 파일을 Host computer의 c:\winnt\ 아래 (중요?? : c:\winnt\symbolham)에 폴더를 만들어 복사한다. Target 컴퓨터에서 작성된  *.c,  *.cpp 파일을 Host computer의 c:\winnt\ 아래(중요??: c:\winnt\symolsourceham)에 폴더를 만들어 복사한다. Null Modem Cable을 연결하고 난후, Host Computer의 Windbg를 수행한다 Windbg의 FILE->Symbol File Path와 FILE->Source File Path를 4, 5에서의 폴더로 세팅한다 Windbg의 Kernel Debug를 선택한다 이제 Target Computer를 부팅한다. Windbg의 Command 창에 디벅메시지가 나타나는지를 살펴본다 2018-09-22

2. Device Driver 작업환경은? : Windbg 설치 가급적 Windbg의 Debug->Source Mode가 체크되어 있는 지를 확인한다 Windbg의 Command 창에 " LM "명령어를 입력하여, 현재 Load된 Module들에 대한 상태들을 살펴본다. 이때 분석하고자 하는 드라이버들에 대한 Symbol들이 잘 올라가 있는 지를 살펴본다 12 번이 여의치 않은 경우 " .reload " 명령어를 입력하여, 새로운 Symbol들로 다시 재 로드하여, 원하는 드라이버 루틴에 대한 *.pdb 파일들이 제대로 Loading 되었는 지를 살펴본다 WIndbg 의 Command 창에서의 명령에 대하여서는 Windbg의 Help->Contents를 크릭하여 도움말을 열고 난후 Reference->Debugger Commands 부분을 읽어 보면 좋을 듯 하다. 2018-09-22

2. Device Driver 작업환경은? : Windbg 설치 16. Windbg의 Command 창에 " x i8042prt!* " 명령어를 입력하여, i8042prt.sys 드라이버 모듈과 관련된 Symbols들을 살펴보기를 바란다. \ Windbg의 Command 창에 " bp i8042prt!I8042KeyboardInterruptService* " 명령어를 입력하여, Debug Break Point를 세팅한 후, 그 결과를 체크하기 위하여, " BL "명령어를 입력하여 본다.  " BC #", " BD # ", " BE # " 명령어는 해당되는 Break Point를 지우거나, Disable, Enable 시킨다 Host Computer에서 Break 하기 위하여서는  Debug->Break을 선택하면 된다 2018-09-22

5. Device Driver 응용사례 : UsbBulk.sys 1. 장치관리자란? 2. Device Driver 작업환경은? 3. Driver 의 구조 4. Plug & Play 5. Device Driver 응용사례 : UsbBulk.sys 6. Application Program 2018-09-22

Kernel Mode Client Driver Layered Driver Architecture Applications User Mode Client Driver Win32 API User Mode Kernel Mode Kernel Mode Client Driver Operating System Kernel File System Drivers Class Driver Port Driver Hardware Bus driver 2018-09-22

2018-09-22

5. Device Driver 응용사례 : UsbBulk.sys 1. 장치관리자란? 2. Device Driver 작업환경은? 3. Driver 의 구조 4. Plug & Play 5. Device Driver 응용사례 : UsbBulk.sys 6. Application Program 2018-09-22

2018-09-22

5. Device Driver 응용사례 : UsbBulk.sys 1. 장치관리자란? 2. Device Driver 작업환경은? 3. Driver 의 구조 4. Plug & Play 5. Device Driver 응용사례 : UsbBulk.sys 6. Application Program 2018-09-22

파일의 구성 Bulkusb.c Bulkpnp.c Busbdbg.c Ioctlblk.c Ocrwblk.c Bulkpwr.c 2018-09-22

Sources파일 TARGETNAME=secbulk TARGETTYPE=DRIVER DRIVERTYPE=WDM TARGETPATH=obj TARGETLIBS=$(DDK_LIB_PATH)\usbd.lib USE_MAPSYM=1 SOURCES= \ BulkUsb.rc \ BusbDbg.c \ BulkUsb.c \ SBulkPnP.c \ BulkPwr.c \ IoctlBlk.c \ OcrwBlk.c 2018-09-22

Bulkusb.c : DriverEntry() NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { …… // Create dispatch points for create, close, unload DriverObject->MajorFunction[IRP_MJ_CREATE] = BulkUsb_Create; DriverObject->MajorFunction[IRP_MJ_CLOSE] = BulkUsb_Close; DriverObject->DriverUnload = BulkUsb_Unload; // User mode DeviceIoControl() calls will be routed here DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = BulkUsb_ProcessIOCTL; // User mode ReadFile()/WriteFile() calls will be routed here DriverObject->MajorFunction[IRP_MJ_WRITE] = BulkUsb_Write; DriverObject->MajorFunction[IRP_MJ_READ] = BulkUsb_Read; // routines for handling system PNP and power management requests DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = BulkUsb_ProcessSysControlIrp; DriverObject->MajorFunction[IRP_MJ_PNP] = BulkUsb_ProcessPnPIrp; DriverObject->MajorFunction[IRP_MJ_POWER] = BulkUsb_ProcessPowerIrp; ….. CreateFile() CloseFile() DeviceIOControl() WriteFile() ReadFile() PowerManager IoCallDriver() 2018-09-22 PnPManager

Bulkusb.c 장치가 장착될 경우에 PnP Manager에 의하여 불리어 진다. // DriverObject->DriverExtension->AddDevice = BulkUsb_PnPAddDevice; BULKUSB_KdPrint( DBGLVL_DEFAULT,("exiting DriverEntry (%x)\n", ntStatus)); return ntStatus; } 장치가 장착될 경우에 PnP Manager에 의하여 불리어 진다. 2018-09-22

Bulkusb.c : BulkUsb_ProcessSysControlIrp NTSTATUS BulkUsb_ProcessSysControlIrp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; irpStack = IoGetCurrentIrpStackLocation (Irp); deviceExtension = DeviceObject->DeviceExtension; stackDeviceObject = deviceExtension->TopOfStackDeviceObject; BulkUsb_IncrementIoCount(DeviceObject); BULKUSB_ASSERT( IRP_MJ_SYSTEM_CONTROL == irpStack->MajorFunction ); IoCopyCurrentIrpStackLocationToNext(Irp); ntStatus = IoCallDriver(stackDeviceObject, Irp); BulkUsb_DecrementIoCount(DeviceObject); return ntStatus; } Next Lower Driver Drivers that do not support WMI by registering as a WMI data provider must pass IRP_MJ_SYSTEM_CONTROL requests to the next lower driver. 2018-09-22

Bulkusb.c : BulkUsb_Read NTSTATUS BulkUsb_Read( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS ntStatus = BulkUsb_StagedReadWrite(DeviceObject, Irp, TRUE); // false to write, true to read return ntStatus; } 2018-09-22

Maximum TransferSize:4096 Bulkusb.c : BulkUsb_StagedReadWrite NTSTATUS BulkUsb_StagedReadWrite( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN BOOLEAN Read ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; … if ( Irp->MdlAddress ) { // could be NULL for 0-len request totalLength = MmGetMdlByteCount(Irp->MdlAddress); } if ( totalLength <= deviceExtension->MaximumTransferSize ) { // for short or zero-len transfers, no need to do the staging; do it in a single request return BulkUsb_SingleUrbReadWrite( DeviceObject, Irp, Read ); } } Maximum TransferSize:4096 2018-09-22

Bulkusb.c : BulkUsb_SingleUrbReadWrite()-1 NTSTATUS BulkUsb_SingleUrbReadWrite( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN BOOLEAN Read) { … Irp->IoStatus.Information = 0; siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER); irpStack = IoGetCurrentIrpStackLocation (Irp); fileObject = irpStack->FileObject; pipeHandle = fileObject->FsContext; ….. if ( Irp->MdlAddress ) { // could be NULL for 0-len request totalLength = MmGetMdlByteCount(Irp->MdlAddress); } urb = BulkUsb_BuildAsyncRequest(DeviceObject, Irp, pipeHandle, Read); deviceExtension->BaseUrb = urb; nextStack = IoGetNextIrpStackLocation(Irp); nextStack->Parameters.Others.Argument1 = urb; 2018-09-22

Bulkusb.c : BulkUsb_SingleUrbReadWrite()-2 nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; IoSetCompletionRoutine( Irp, // irp to use BulkUsb_SimpleReadWrite_Complete, // routine to call when irp is done DeviceObject, // we pass our FDO as context to pass routine TRUE, // call on success TRUE, // call on error TRUE); BulkUsb_IncrementIoCount(DeviceObject); ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp ); return ntStatus; } 2018-09-22

Data Structure : IRP typedef struct _IRP { . . PMDL MdlAddress; ULONG Flags; union { struct _IRP *MasterIrp; PVOID SystemBuffer; } AssociatedIrp; IO_STATUS_BLOCK IoStatus; .. PDRIVER_CANCEL CancelRoutine; PVOID UserBuffer; } Tail; } IRP, *PIRP; Pointer to an MDL describing a user buffer for an IRP_MJ_READ or IRP_MJ_WRITE request if the driver set up its device object(s) for direct I/O . AssociatedIrp.SystemBuffer Pointer to a system-space buffer for one of the following: (1) a transfer request to a driver that set up its device object(s) requesting buffered I/O; (2) an IRP_MJ_DEVICE_CONTROL request, (3) an IRP_MJ_INTERNAL_DEVICE_CONTROL request with an I/O control code that was defined with METHOD_BUFFERED 2018-09-22

Data Structure : IO_STACK_LOCATION typedef struct _IO_STACK_LOCATION { UCHAR MajorFunction; UCHAR MinorFunction; UCHAR Flags; UCHAR Control; union { // Parameters for IRP_MJ_CREATE struct { PIO_SECURITY_CONTEXT SecurityContext; ULONG Options; USHORT POINTER_ALIGNMENT FileAttributes; USHORT ShareAccess; ULONG POINTER_ALIGNMENT EaLength; } Create; // Parameters for IRP_MJ_READ struct { ULONG Length; ULONG POINTER_ALIGNMENT Key; LARGE_INTEGER ByteOffset; } Read; …. PDEVICE_OBJECT DeviceObject; PFILE_OBJECT FileObject; . . } IO_STACK_LOCATION, *PIO_STACK_LOCATION; 2018-09-22

Data Structure : FILE_OBJECT Accessible Fields PDEVICE_OBJECT DeviceObject Pointer to the device object on which the file is opened. PVOID FsContext Pointer to whatever optional state a driver maintains about the file object; otherwise, NULL. PVOID FsContext2 Pointer to whatever additional state a driver maintains about the file object; otherwise, NULL. UNICODE_STRING FileName Is the name of the file opened on the device, or the Length of the string is zero if the device represented by DeviceObject is being opened. 2018-09-22

2018-09-22

2018-09-22

2018-09-22

5. Device Driver 응용사례 : UsbBulk.sys 1. 장치관리자란? 2. Device Driver 작업환경은? 3. Driver 의 구조 4. Plug & Play 5. Device Driver 응용사례 : UsbBulk.sys 6. Application Program 2018-09-22

아지시스템에서 제공하는 2410 관련 CD 에 들어 있는 rwbulk.exe ( Web Disk 에서 다운 로드 할 것) Application Program 아지시스템에서 제공하는 2410 관련 CD 에 들어 있는 rwbulk.exe ( Web Disk 에서 다운 로드 할 것) MBA 2440 보드를 호스트 컴퓨터와 연결 호스트컴퓨터에서 DNW.exe 를 가동하고 MBA 를 리셋한후 18번 메뉴를 선택한 후에 다시 1번 메뉴를 세팅하여 target MBA 2440 보드의 USB Client (Device) 기능을 발휘시킨다. 호스트 컴퓨터의 rwbulk.exe 를 가동한 후 “rwbulk –r 128” 을 수행하여 타겟 MBA2440 으로부터 USB 를 통하여 data 를 전송받아본다. 3. 단계가 잘 되지 않을 경우, dnw.exe 의 USB Port-> Rx Test 를 클릭하여 타겟 MBA2440 으로부터 USB 룰 통하여 data 가 잘 전송되는지 체크하여본다. 2018-09-22

Application Program DNW.exe 프로그램의 작동: USB Port-> Rx Test 2018-09-22

Application Program Rwbulk.exe 프로그램의 작동: rwbulk –r 128 2018-09-22

Application Program Rwbulk.exe 프로그램이 작동될 때, dnw.exe 도 MBA2440 보드가 USB Device 로 작동되게 하기 위하여 가동되어야 하며, 여기서 18번 메뉴와 이에 대한 1번 서브를 선택하여야 한다. 이러한 처리가 있어야만 MBA2440 보드가 usb Device 로 가동되며, 따라서 이 때 dnw.exe 의 USB Port -> Rx Test 를 수행하여 MBA2440 보드의 USB Device 기능이 잘 발휘되는가를 살펴본다. 다음 그림에서는 SECBULK.SYS 와 관련하여 두개의 장치가 가동중임을 알 수 있으며, 하나는 DNW.exe 와 다른 하나는 rwbulk.exe 와 SECBULK.SYS 와 연계하여 작동하고 있음을 보여주고 있다. USBPDO-12 2018-09-22

Application Program USB Client 의 장치명 2개가 사용되고 있다. 2018-09-22

rwbulk.c 에 대하여 MS Visual C 로 작동시키기 위한 절차 Application Program rwbulk.c 에 대하여 MS Visual C 로 작동시키기 위한 절차 rwbulk.c 를 MS Visual C  tool을 이용하여 open 한다. Visual C 상황에서 Build->Rebuild ALL를 수행하여 본다.  이 후 Project 를  만들 것이냐? 물음이 들어오면 yes를 응답한다. 다시 Visual C 상황에서 Build->Rebuild ALL를 수행하여 본다.  당연히 ERROR 가 발생된다. ERROR 에 대처한 다음 절차를 밟는다 Tools->Options 를 선택하여 Build Directory 탭을 선정하고 include files 에 대한 directory를 D:\WINDDK\2600.1106\INC\DDK\WXP 로 세팅한다. Project->Settings를 클릭하고나서 나타나는 대화상자에서  Link 탭을 선정한다. 그리고 나서 Object/Library modules  부분에 setupapi.lib usbd.lib를 추가 한다. Tools->Options 를 선택하여 Build Directory 탭을 선정하고 library files 에 대한 directory를 D:\WINDDK\2600.1106\LIB\WXP\I386로 세팅한다. 2018-09-22

rwbulk.c 에 대하여 MS Visual C 로 작동시키기 위한 절차 Application Program rwbulk.c 에 대하여 MS Visual C 로 작동시키기 위한 절차 Project->Settings 의 Debug 탭을 선택하고 Program Argument 에 “ –r 128” 을 입력한다. Rwbulk.c 의 main() 함수의 parse() 부분에 debug break 을 세팅하고 나서 build->Start debug 을 수행하면서 디버깅하여 본다. 2018-09-22

Application Program 2018-09-22

Application Program 다음과 같이 기존의 main() 루틴에 dump() 를 추가하여 USB Device 로 부터 읽어온 내용을 command 창에 나타낸다. … printf("<%s> R (%04.4d) : request %06.6d bytes -- %06.6d bytes read\n", inPipe, i, ReadLen, nBytesRead); //HAM printf("Dumping read buffer\n"); dump( pinBuf, nBytesRead ); if (fWrite) { ….. 2018-09-22

Application Program 2018-09-22

Application Program TIP : 디버깅 모드에서 작동시키면 작동이 되지 않음을 유의하시기 바랍니다. 따라서 USB read 작동시는 디버깅 상태에서 Test 가 되지 않음을 유념하시기 바랍니다. 2018-09-22

- END - 2018-09-22