<세마포어란?>
[OS] 뮤텍스, 세마포어, 모니터 — 그냥저냥끄적끄적 (tistory.com)


# 스레드 동기화의 교착상태 문제 해결

동시 수행 프로그램을 os161운영체제 환경에서 스레드들을 사용해서 작성, 주어진 데드락 문제 해결하기. 그리고 구현한 결과를 설명하는 보고서 작성하여 제출하기.

관련자료: how to build tools and os161, os161과제 관련 원천코드


# build tools and os 161

주어진 파일 압축을 풀고 /home/유저이름 에 넣는다. 주어진 폴더 안에 os161_gz가 있는데 이걸 다시 ~/os161_src로 옮겼다. (mac용 코드는 필요없음)


<유의할점 1>
스크립트 내에서 ~(물결) 표시를 사용하고 있는데
root 상태에서와 처음 상태에서 지칭하는 '~'(물결표시)의 위치가 다르다. root상태에서 exit하자
위 내용 실행할때 문제가 된다. 과제 내용중 맨 마지막 줄은 없는데, 추가해줘야 한다.


<유의할점 2>
압축을 풀기 전 위와 같은 상태로 파일 내용물 배치. os161_gz 폴더 안에 또 폴더가 있는데, 그 내용물은 꺼내서 한 폴더에 놓아야 한다. 위 사진에서 os161_gz폴더는 비어있거나 없어도 된다.
이렇게 안해도 빌드는 될것 같은데... 교수님이 이렇게 된 상태로 보여주셔서 이렇게 세팅하고 진행했다.



tool폴더 만들어진 상태


src 폴더 내용 압축을 푼 상태


<??>
cd $BINUTILS161
이 부분에서 루트 경로에서 처음에 설정한 변수인
BINUTILS161="binutils-2.24+os161-2.1" 이것을 찾게 된다.
위 폴더는 바로 찾을수 있는데, 직접 들어가서 그 아래 부분부터 스크립트 실행하면 된다. 학교에서는 그냥 되는걸로 기억하는데 왜 집에서는 다르지?



PRE_CC=$CC
PRE_CFLAGS=$CFLAGS
CC=gcc
CFLAGS=

echo '*** Building binutils ***'
cd $BINUTILS161
find . -name '*.info' | xargs touch
touch intl/plural.c
./configure --nfp --disable-werror --target=mips-harvard-os161 --prefix=$HOME/tools/os161 2>&1 | tee ../binutils.log
make 2>&1 | tee -a ../binutils.log
make install 2>&1 | tee -a ../binutils.log
cd ..
echo '*** Finished building binutils ***'
#rm -rf $BINUTILS161


결과


<??>
echo '*** Building gcc ***'
PATH=$HOME/tools/sys161/bin:$HOME/tools/os161/bin:$PATH
export PATH
cd $GCC161
find . -name '*.info' | xargs touch
touch intl/plural.c
mkdir ../gcc-build
cd ../gcc-build
../$GCC161/configure --enable-languages=c,lto -nfp --disable-shared --disable-threads --disable-libmudflap --disable-libssp --disable-libstdcxx --disable-nls --target=mips-harvard-os161 --prefix=$HOME/tools/os161 2>&1 | tee ../gcc.log
make 2>&1 | tee -a ../gcc.log
make install 2>&1 | tee -a ../gcc.log
cd ..
echo '*** Finished building gcc ***'
#rm -rf $GCC161
#rm -rf gcc-build


cd $GCC161
이 부분에서 처음과 같은 문제가 생겨서 해당 디렉토리로 직접 입력하고 아래부터 실행했다.
../$GCC161/configure ~~ 부분에서 다시 문제가 생기는것 같아서
다시 해당 디렉토리로 이동하고 ./configure~~ 부분 실행(./ 필요하다)


<??>
http://gcc.gnu.org/install/prerequisites.html for additional info.  If
you obtained GMP, MPFR and/or MPC from a vendor distribution package,
make sure that you have installed both the libraries and the header
files.  They may be located in separate packages.
s~~~2@ubuntu00002004:~/os161_src/gcc-4.8.3+os161-2.1$ make 2>&1 | tee -a ../gcc.log
make: *** No targets specified and no makefile found.  Stop.
s~~~~2@ubuntu00002004:~/os161_src/gcc-4.8.3+os161-2.1$ make install 2>&1 | tee -a ../gcc.log
make: *** No rule to make target 'install'.  Stop.

configure 스크립트 실행 중 발생한 오류는 GCC를 빌드하기 위해 필요한 라이브러리인 GMP, MPFR, MPC가 설치되어 있지 않기 때문입니다. 이를 해결하기 위해 필요한 라이브러리를 설치하고 다시 configure 명령어를 실행해야 합니다.

sudo apt-get update
sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev
설치하고 실행 안된 부분부터 다시 실행. 이미 실행된 부분 다시 실행해도 큰 문제없고 이전 과정이 문제 없었다면 빠르게 넘어간다.

./configure ~~ 다시 이 부분 실행시 방금 설치한 라이브러리고 GCC를 빌드하는것으로 보인다. (오래걸림)  <- 이게 building gdb부분(다음내용) 인데 실수했다.



<오류>

이 오류는 libgcc.mvars 파일을 찾을 수 없다는 것입니다. 이 파일은 GCC 빌드 과정에서 필요하며, 파일이 없으면 빌드가 실패하게 됩니다. 이 문제는 여러 가지 원인으로 발생할 수 있습니다. 가장 일반적인 원인은 빌드 과정 중 파일이 손상되었거나, 빌드 스크립트가 제대로 실행되지 않아서입니다.


s~~~~2@ubuntu00002004:~/os161_src/gcc-4.8.3+os161-2.1$ make distclean
make[1]: Entering directory '/home/s~~~2/os161_src/gcc-4.8.3+os161-2.1'
Doing distclean in mips-harvard-os161/libgcc
make[2]: Entering directory '/home/s~~~2/os161_src/gcc-4.8.3+os161-2.1/mips-harvard-os161/libgcc'
Makefile:162: ../.././gcc/libgcc.mvars: No such file or directory
make[2]: *** No rule to make target '../.././gcc/libgcc.mvars'.  Stop.
make[2]: Leaving directory '/home/s~~~2/os161_src/gcc-4.8.3+os161-2.1/mips-harvard-os161/libgcc'
make[1]: *** [Makefile:10318: distclean-target-libgcc] Error 1
make[1]: Leaving directory '/home/s~~~2/os161_src/gcc-4.8.3+os161-2.1'
make: *** [Makefile:1818: do-distclean] Error 2

make distclean 할 경우 문제가 발생한다 (정상적으로 진행시 필요없음)
현재 make distclean 명령어를 실행하려 했으나 libgcc.mvars 파일이 없어서 실패한 상황입니다. 이 문제를 해결하기 위해 몇 가지 단계를 더 시도해 볼 수 있습니다.

~~~~ : find ../gcc-4.8.3+os161-2.1 -name libgcc.mvars
../gcc-4.8.3+os161-2.1/host-x86_64-unknown-linux-gnu/gcc/libgcc.mvars
여기 있는데 왜 못찾는거


참고

위 소스 디렉토리와 다른 곳에서 빌드해야 문제가 안생기는데, 내가 스크립트를 한줄씩 실행하다보니 실수한것으로 보인다. os161_src에 gcc-build라는 비어있는 폴더만 남아있다...


cd ~/os161_src
rm -rf gcc-build
rm -rf gcc-4.8.3+os161-2.1
tar -xzf path/to/gcc-4.8.3+os161-2.1.tar.gz
mkdir -p ~/os161_src/gcc-build
cd ~/os161_src/gcc-build
이 부분은 위 방법으로 초기화하고 다시 진행했다. 스크립트 한 문단마다 압축파일에서 나온 폴더 하나로 작업하고 있으므로 잘못될경우 비슷한 방법으로 진행하면 된다.



앞에 과정까지 진행하고, gcc-build폴더 만드는 부분에 가서 ../gcc-4.8.3+os161-2.1/configure --enable-la~~ 이런식으로 실행했다. $GCC161 = gcc-4.8.3+os161-2.1 이 부분만 직접입력(tab눌러도 된다)



계속 진행하다가
mkdir -p ~/os161/src
cd ~/os161/src
tar xvfz ~/os161_gz/$OS161
이 부분은 os161_gz가 아닌 os161_src로 바꾼다.

./configure --ostree=$HOME/os161/root

bmake
bmake install
bmake가 안된다면 필요한것 설치해주면 된다.


cd kern/conf
./config DUMBVM


cd ~/os161/src/kern/compile/DUMBVM
bmake depend
bmake
bmake install


cp ~/os161_gz/sys161.conf.sample ~/os161/root/sys161.conf

cd ~/os161/root
sys161 kernel
echo '*** Done ***'
윗줄에 os161_gz를 os161_src로 바꾼다.


끝??

빌드는 완료한것 같다.


#/bin/bash

SYS161="sys161-2.0.3"
BINUTILS161="binutils-2.24+os161-2.1"
GCC161="gcc-4.8.3+os161-2.1"
GDB161="gdb-7.8+os161-2.1"
#MIRROR="http://www.eecs.harvard.edu/~dholland/os161/download"
#MIRROR="http://www.ece.ubc.ca/~os161/download"

#echo '*** Updating appliance ***'
#update50

#echo '*** Installing Ubuntu packages ***'
sudo apt-get -y update
sudo apt-get -y install linux-source vim libncurses5 libncurses5-dev ctags build-essential
sudo apt-get -y install bmake ncurses-dev libmpc-dev

cd ~
mkdir ~/tools
cd ~/tools
mkdir -p os161 os161/bin os161/src
mkdir sys161 sys161/bin

#echo '*** Downloading OS/161 toolchain ***'
#wget $MIRROR/$BINUTILS161.tar.gz
#wget $MIRROR/$GCC161.tar.gz
#wget $MIRROR/$GDB161.tar.gz
#wget $MIRROR/$SYS161.tar.gz

echo '*** Unpacking OS/161 toolchain ***'
for file in *.tar.gz; do  
    tar -xzf $file
#    rm -f $file
done

PRE_CC=$CC
PRE_CFLAGS=$CFLAGS
CC=gcc
CFLAGS=

echo '*** Building binutils ***'
cd $BINUTILS161
find . -name '*.info' | xargs touch
touch intl/plural.c
./configure --nfp --disable-werror --target=mips-harvard-os161 --prefix=$HOME/tools/os161 2>&1 | tee ../binutils.log
make 2>&1 | tee -a ../binutils.log
make install 2>&1 | tee -a ../binutils.log
cd ..
echo '*** Finished building binutils ***'
#rm -rf $BINUTILS161

echo '*** Building gcc ***'
PATH=$HOME/tools/sys161/bin:$HOME/tools/os161/bin:$PATH
export PATH
cd $GCC161
find . -name '*.info' | xargs touch
touch intl/plural.c
mkdir ../gcc-build
cd ../gcc-build
../$GCC161/configure --enable-languages=c,lto -nfp --disable-shared --disable-threads --disable-libmudflap --disable-libssp --disable-libstdcxx --disable-nls --target=mips-harvard-os161 --prefix=$HOME/tools/os161 2>&1 | tee ../gcc.log
make 2>&1 | tee -a ../gcc.log
make install 2>&1 | tee -a ../gcc.log
cd ..
echo '*** Finished building gcc ***'
#rm -rf $GCC161
#rm -rf gcc-build

echo '*** Building gdb ***'
cd $GDB161
find . -name '*.info' | xargs touch
touch intl/plural.c
./configure --target=mips-harvard-os161 --prefix=$HOME/tools/os161 --disable-werror --disable-sim 2>&1 | tee ../gdb.log
make 2>&1 | tee -a ../gdb.log
make install 2>&1 | tee -a ../gdb.log
cd ..
echo '*** Finished building gdb ***'
#rm -rf $GDB161

echo '*** Building System/161 ***'
cd $SYS161
./configure --prefix=$HOME/tools/sys161 mipseb 2>&1 | tee ../sys161.log
make 2>&1 | tee -a ../sys161.log
make install 2>&1 | tee -a ../sys161.log
cd ..
mv $SYS161 sys161
echo '*** Finished building System/161 ***'

cd os161/bin
for file in *; do
    ln -s $file ${file:13}
done
cd ../..

cd ~
echo 'PATH=$HOME/tools/sys161/bin:$HOME/tools/os161/bin:$PATH' >> $HOME/.bashrc
echo 'set path = ($path $HOME/tools/os161/bin $HOME/tools/sys161/bin)' >> $HOME/.cshrc

CC=$PRE_CC
CFLAGS=$PRE_CFLAGS
OS161="os161-CPEN331-base-2016.tar.gz"

mkdir -p ~/os161/src
cd ~/os161/src
tar xvfz ~/os161_gz/$OS161

./configure --ostree=$HOME/os161/root

bmake
bmake install

cd kern/conf
./config DUMBVM

cd ~/os161/src/kern/compile/DUMBVM
bmake depend
bmake
bmake install

cp ~/os161_gz/sys161.conf.sample ~/os161/root/sys161.conf

cd ~/os161/root
sys161 kernel
echo '*** Done ***'
이 과정 약간 고쳐서 진행한것
코드 뒷부분은 os161_gz 이렇게 폴더 이름 안바꾸고 했으면 그대로 진행 가능했을것 같은데..
일단 가상머신 백업부터 하자


# 데드락 문제 해결

주어진 동시 수행 프로그램을 os161 운영체제에서 스레드를 사용하여 작성하고, 다음의 데드락 문제를 해결하자.
미리 정의된 수인 32개의 스레드를 제공하는 기본코드가 ‘os161/src/ kern/test/synchtest.c’에 있다. 이걸 수정하여 스레드들이 세마포어를 사용해서 데드락이 없이 자동차들이 교차로를 통과하도록 프로그램을 작성하기(synch.h 참고)



sys161.conf 파일 편집하여 28 random autoseed를 28 random seed = 1로 수정하여 난수 생성기에서 생성할 시드를 고쳐서 디버그를 쉽게 하자.

DUMBVM으로 커널을 구성하면 솔루션을 실행하기 위한 드라이버 코드와 추가 메뉴 옵션이 자동으로 컴파일 된다고 한다...



문제: 흑석동에 있는 주요 교차로를 통과하는 교통량은 지난 몇 년 동안 증가했습니다. 이제 막대한 교착 상태로 인해 푸앙대학교로 등교하거나 출근하는 사람은 교통이 교차로를 통과하는 데보다 효율적인 방법이 필요하다는 사실을 인정하게 되었습니다. 귀하의 임무는 세마포어를 사용하여 솔루션을 설계하고 구현하는 것입니다. 구현을 해서, 교착상태를 어떻게 해결하는 지를 설명하는 보고서를 작성해서, 제출하세요. 


첫번째 과제 (3점): 아래에 주어진 문제 중에 ‘(어려운 과제)’라고 표시되지않은 모든 문제를 주의 깊게 읽어서 해결합니다. 
두번째 과제 (3점): ‘(어려운 과제)’라고 언급 된 3가지 문제들을 모두 해결합니다.  
 


교차점 모델링

자동차는 직진, 우회전, 좌회전의 세가지 통과를 목적으로 교차로에 진입하게 됩니다. 이 문제의 목적을 위해 다음과 같이 교차로를 사분면들로 나누면, 차량의 교차로의 통과는 교차점의 한 부분, 두 부분 또는 세 부분을 통한 진행으로 표현됩니다. (간략히 하기 위해 U 턴 교차로에서는 발생하지 않음). 


예를 들어 차가 북쪽에서 교차로에 접근하면, 그것이 어디로 가느냐에 따라 다음과 같이 교차로를 진행합니다 :
• 우회전 : NW (어려운 과제)
• 직진 : NW-SW
• 좌회전 : NW-SW-SE (어려운 과제)

구현
우리는 교차로 모델을 제공하였습니다. 요구 사항은 다음과 같습니다.
• 교차로의 같은 부분에 2 대의 자동차가 동시에 있을 수는 없습니다. (이것을 사고라고 부른다.)
• 다른 방향에서 오는 트래픽이 무한정 기다리는 꼬리물기를 하지 못하게 하면서, 트래픽 흐름을 개선해야합니다. (어려운 과제)
• 각 차량은 차량 번호, 접근 방향 및 목적지 방향을 나타내는 출력을 교차로에 접근, 진입 및 떠날 때 인쇄해야 합니다. 인쇄용으로 제공된 메시지 기능(message function)을 호출해야합니다.

이 문제에 대한 기본이 되는 프로그램은 ‘os161/src/kern/test/synchtest.c’에 있습니다. 그 파일의 semtest()는 32 개의 자동차들을 쓰레드들로 생성하도록 프로그램으로 변형하여 사용할 수 있습니다. 이 함수는 ‘sys161 kernel’을 실행하면 나타나는 메뉴에서 ‘sy1’을 입력하면 실행할 수 있습니다. 각 쓰레드는 semtestthread() 함수인데, 이 함수를 수정해서 회전 각을 임의의 방향으로 할당하고, 각에 따라서 gostraight(), turnright() 및 turnleft() 함수를 불러서 각각의 방향으로 교차로를 통과하기 위해서 필요한 자원들을 확보하는 해결책을 구현하는데 사용할 수 있습니다.

구현을 했으면, 교착상태를 어떻게 해결하는 지를 설명하는 보고서를 작성해서 제출하세요. 



숙제를 위해서 컴파일하고 실행하는 방법은 다음의 내용을 참조하기 바랍니다. 
1. Configure a kernel named DUMBVM.
  % cd ~/csc369/src/kern/conf
  % ./config DUMBVM
2. Build the DUMBVM kernel.
  % cd ../compile/ DUMBVM
  % bmake depend
  % bmake
3. Install the DUMBVM kernel.
  % bmake install

That's it! You should now have a kernel, and the user level utilities installed under ~/os161/root.
Running your kernel
1. Run the machine simulator on your operating system.
  % sys161 kernel

As the system boots, it will print some messages on the console, including a list of all the devices that are found. It finishes by displaying the OS/161 kernel prompt.
2. At the prompt, type ? to see the menu.
3. You can also type ?t at the menu prompt to display a list of test programs. Try running some of them.
4. You can type sy1 at the manu prompt to run the test program for the multiple threading and semaphores.


<원본 synchtest.c>
/*
 * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
 *  The President and Fellows of Harvard College.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * Synchronization test code.
 */

#include <types.h>
#include <lib.h>
#include <clock.h>
#include <thread.h>
#include <synch.h>
#include <test.h>

#define NSEMLOOPS     63
#define NLOCKLOOPS    120
#define NCVLOOPS      5
#define NTHREADS      32

static volatile unsigned long testval1;
static volatile unsigned long testval2;
static volatile unsigned long testval3;
static struct semaphore *testsem;
static struct lock *testlock;
static struct cv *testcv;
static struct semaphore *donesem;

static
void
inititems(void)
{
    if (testsem==NULL) {
        testsem = sem_create("testsem", 2);
        if (testsem == NULL) {
            panic("synchtest: sem_create failed\n");
        }
    }
    if (testlock==NULL) {
        testlock = lock_create("testlock");
        if (testlock == NULL) {
            panic("synchtest: lock_create failed\n");
        }
    }
    if (testcv==NULL) {
        testcv = cv_create("testlock");
        if (testcv == NULL) {
            panic("synchtest: cv_create failed\n");
        }
    }
    if (donesem==NULL) {
        donesem = sem_create("donesem", 0);
        if (donesem == NULL) {
            panic("synchtest: sem_create failed\n");
        }
    }
}

static
void
semtestthread(void *junk, unsigned long num)
{
    int i;
    (void)junk;

    /*
     * Only one of these should print at a time.
     */
    P(testsem);
    kprintf("Thread %2lu: ", num);
    for (i=0; i<NSEMLOOPS; i++) {
        kprintf("%c", (int)num+64);
    }
    kprintf("\n");
    V(donesem);
}

int
semtest(int nargs, char **args)
{
    int i, result;

    (void)nargs;
    (void)args;

    inititems();
    kprintf("Starting semaphore test...\n");
    kprintf("If this hangs, it's broken: ");
    P(testsem);
    P(testsem);
    kprintf("ok\n");

    for (i=0; i<NTHREADS; i++) {
        result = thread_fork("semtest", NULL, semtestthread, NULL, i);
        if (result) {
            panic("semtest: thread_fork failed: %s\n",
                  strerror(result));
        }
    }

    for (i=0; i<NTHREADS; i++) {
        V(testsem);
        P(donesem);
    }

    /* so we can run it again */
    V(testsem);
    V(testsem);

    kprintf("Semaphore test done.\n");
    return 0;
}

static
void
fail(unsigned long num, const char *msg)
{
    kprintf("thread %lu: Mismatch on %s\n", num, msg);
    kprintf("Test failed\n");

    lock_release(testlock);

    V(donesem);
    thread_exit();
}

static
void
locktestthread(void *junk, unsigned long num)
{
    int i;
    (void)junk;

    for (i=0; i<NLOCKLOOPS; i++) {
        lock_acquire(testlock);
        testval1 = num;
        testval2 = num*num;
        testval3 = num%3;

        if (testval2 != testval1*testval1) {
            fail(num, "testval2/testval1");
        }

        if (testval2%3 != (testval3*testval3)%3) {
            fail(num, "testval2/testval3");
        }

        if (testval3 != testval1%3) {
            fail(num, "testval3/testval1");
        }

        if (testval1 != num) {
            fail(num, "testval1/num");
        }

        if (testval2 != num*num) {
            fail(num, "testval2/num");
        }

        if (testval3 != num%3) {
            fail(num, "testval3/num");
        }

        lock_release(testlock);
    }
    V(donesem);
}


int
locktest(int nargs, char **args)
{
    int i, result;

    (void)nargs;
    (void)args;

    inititems();
    kprintf("Starting lock test...\n");

    for (i=0; i<NTHREADS; i++) {
        result = thread_fork("synchtest", NULL, locktestthread,
                     NULL, i);
        if (result) {
            panic("locktest: thread_fork failed: %s\n",
                  strerror(result));
        }
    }
    for (i=0; i<NTHREADS; i++) {
        P(donesem);
    }

    kprintf("Lock test done.\n");

    return 0;
}

static
void
cvtestthread(void *junk, unsigned long num)
{
    int i;
    volatile int j;
    struct timespec ts1, ts2;

    (void)junk;

    for (i=0; i<NCVLOOPS; i++) {
        lock_acquire(testlock);
        while (testval1 != num) {
            gettime(&ts1);
            cv_wait(testcv, testlock);
            gettime(&ts2);

            /* ts2 -= ts1 */
            timespec_sub(&ts2, &ts1, &ts2);

            /* Require at least 2000 cpu cycles (we're 25mhz) */
            if (ts2.tv_sec == 0 && ts2.tv_nsec < 40*2000) {
                kprintf("cv_wait took only %u ns\n",
                    ts2.tv_nsec);
                kprintf("That's too fast... you must be "
                    "busy-looping\n");
                V(donesem);
                thread_exit();
            }

        }
        kprintf("Thread %lu\n", num);
        testval1 = (testval1 + NTHREADS - 1)%NTHREADS;

        /*
         * loop a little while to make sure we can measure the
         * time waiting on the cv.
         */
        for (j=0; j<3000; j++);

        cv_broadcast(testcv, testlock);
        lock_release(testlock);
    }
    V(donesem);
}

int
cvtest(int nargs, char **args)
{

    int i, result;

    (void)nargs;
    (void)args;

    inititems();
    kprintf("Starting CV test...\n");
    kprintf("Threads should print out in reverse order.\n");

    testval1 = NTHREADS-1;

    for (i=0; i<NTHREADS; i++) {
        result = thread_fork("synchtest", NULL, cvtestthread, NULL, i);
        if (result) {
            panic("cvtest: thread_fork failed: %s\n",
                  strerror(result));
        }
    }
    for (i=0; i<NTHREADS; i++) {
        P(donesem);
    }

    kprintf("CV test done\n");

    return 0;
}

////////////////////////////////////////////////////////////

/*
 * Try to find out if going to sleep is really atomic.
 *
 * What we'll do is rotate through NCVS lock/CV pairs, with one thread
 * sleeping and the other waking it up. If we miss a wakeup, the sleep
 * thread won't go around enough times.
 */

#define NCVS 250
#define NLOOPS 40
static struct cv *testcvs[NCVS];
static struct lock *testlocks[NCVS];
static struct semaphore *gatesem;
static struct semaphore *exitsem;

static
void
sleepthread(void *junk1, unsigned long junk2)
{
    unsigned i, j;

    (void)junk1;
    (void)junk2;

    for (j=0; j<NLOOPS; j++) {
        for (i=0; i<NCVS; i++) {
            lock_acquire(testlocks[i]);
            V(gatesem);
            cv_wait(testcvs[i], testlocks[i]);
            lock_release(testlocks[i]);
        }
        kprintf("sleepthread: %u\n", j);
    }
    V(exitsem);
}

static
void
wakethread(void *junk1, unsigned long junk2)
{
    unsigned i, j;

    (void)junk1;
    (void)junk2;

    for (j=0; j<NLOOPS; j++) {
        for (i=0; i<NCVS; i++) {
            P(gatesem);
            lock_acquire(testlocks[i]);
            cv_signal(testcvs[i], testlocks[i]);
            lock_release(testlocks[i]);
        }
        kprintf("wakethread: %u\n", j);
    }
    V(exitsem);
}

int
cvtest2(int nargs, char **args)
{
    unsigned i;
    int result;

    (void)nargs;
    (void)args;

    for (i=0; i<NCVS; i++) {
        testlocks[i] = lock_create("cvtest2 lock");
        testcvs[i] = cv_create("cvtest2 cv");
    }
    gatesem = sem_create("gatesem", 0);
    exitsem = sem_create("exitsem", 0);

    kprintf("cvtest2...\n");

    result = thread_fork("cvtest2", NULL, sleepthread, NULL, 0);
    if (result) {
        panic("cvtest2: thread_fork failed\n");
    }
    result = thread_fork("cvtest2", NULL, wakethread, NULL, 0);
    if (result) {
        panic("cvtest2: thread_fork failed\n");
    }

    P(exitsem);
    P(exitsem);

    sem_destroy(exitsem);
    sem_destroy(gatesem);
    exitsem = gatesem = NULL;
    for (i=0; i<NCVS; i++) {
        lock_destroy(testlocks[i]);
        cv_destroy(testcvs[i]);
        testlocks[i] = NULL;
        testcvs[i] = NULL;
    }

    kprintf("cvtest2 done\n");
    return 0;
}



OS/161 base system version 1.99.08 Copyright (c) 2000, 2001-2005, 2008-2011, 2013, 2014 President and Fellows of Harvard College. All rights reserved. Put-your-group-name-here's system version 0 (DUMBVM #1) 292k physical memory available Device probe... lamebus0 (system main bus) emu0 at lamebus0 ltrace0 at lamebus0 ltimer0 at lamebus0 beep0 at ltimer0 rtclock0 at ltimer0 lrandom0 at lamebus0 random0 at lrandom0 lhd0 at lamebus0 lhd1 at lamebus0 lser0 at lamebus0 con0 at lser0 cpu0: MIPS/161 (System/161 2.x) features 0x0 OS/161 kernel [? for menu]: sy1 Starting semaphore test... If this hangs, it's broken: ok Thread 0: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Thread 1: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Thread 2: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB Thread 3: CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC Thread 4: DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD Thread 5: EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE Thread 6: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF Thread 7: GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG Thread 9: IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII Thread 10: JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ Thread 11: KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK Thread 12: LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL Thread 13: MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM Thread 14: NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN Thread 15: OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO Thread 16: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP Thread 17: QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ Thread 18: RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR Thread 19: SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS Thread 20: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT Thread 21: UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU Thread 22: VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV Thread 23: WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Thread 24: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Thread 25: YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY Thread 26: ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ Thread 27: [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ Thread 28: \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Thread 29: ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] Thread 30: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Thread 31: _______________________________________________________________ Thread 8: HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH Semaphore test done. Operation took 4.803818160 seconds OS/161 kernel [? for menu]:

이미 세마포어 테스트가 구현되어 있다.
코드 안에 struct semaphore *testsem; 부분이 있다.
다른 예제 코드들 보면 새로 세마포어 선언해서 사용하는듯


<참고>

원래 구현된 세마포어 테스트는 sy1 입력하면 계속 반복되는데
다른 예제를 가져와서 구현하면 한번만 테스트가 가능하고 다시 sy1 입력하면 os161이 종료된다는 문제점이 있다.

그리고 처음 시작부분에서 이상한 문자열과 공백이 섞여서 출력된다는 문제점이 있다
과제를 일찍 하고 교수님께 이걸 물어봤어야 했는데...

이걸 해결하려다가 아직도 과제 완성을 못하고 있다
그냥 적당히 했으면 지난주에 끝났을걸...


여기서 출력을 더 늘리면 글이랑 숫자가 다 깨져서 나온다.
지금 상태는 sy1로 실행시 밑에 공백과 이상한 글자가 없이 깨끗하게 나온다.
진입, 빠져나가는 상태 추가시 출력 망가지는 문제로 완전하게 구현은 못했다. 출력을 앞뒤로 매번 잠그라는데 잘 안된다. 여러가지로 시도했지만...
좀 깎일듯... ㅠㅠ