[출처] http://www.sci.brooklyn.cuny.edu/~goetz/codeblocks/glut/

Using OpenGL & GLUT in Code::Blocks

Download Code::Blocks
http://www.sci.brooklyn.cuny.edu/~goetz/codeblocks/

Download the GLUT bin file (first download link) from:
http://www.xmission.com/~nate/glut.html

    After you download and open the GLUT bin zip file, you will need to:
  • Copy glut32.dll to c:\windows\system,
  • Copy glut32.lib to c:\program files\mingw\lib, and
  • Copy glut.h to c:\program files\mingw\include\GL.
  • These are default locations, your paths may be different. But basically, you place the .lib and .h files in the location of your compiler (in this case mingw). The .dll file goes in the windows system directory.

Now you are ready to start Code::Blocks and make a new project.


Open up Code::Blocks. Start a new Project by going to File, New, Project.


Select to make a new GLUT project and press Go to continue.



Press Next at this menu


Give a project title, and a location where to create the project and then press Next.



Let Code::Blocks know where you stored your GL files, then press Next.


Leave these unchanged, and press Finish.



In the manager window (viewable by pressing Shift-F2), open up the sample source file by double clicking on it. To make your program work, you will need to add at line 14:
#include <windows.h>


You will need to make a small change to the project's Build Options. Go to Project, Build Options.


Select the Linker tab and press Add in the Link Libraries area.


Press on the ... button to select a library to add. You need to add the glut32.lib library. Locate this from the directory you placed it in before.


After you add the library, it will ask if you want to keep the path relative. Select No.


Press OK to select the library.


Press OK to close the Project's Build Options.

Press F9 to do a Build & Run of your project.

After a while you'll get some warnings. Ignore the warnings. If you get errors, check the steps above to make sure you added in the new line at 14, and setup project to use the glut32.lib library file to use.

Hopefully you'll get a program displaying the following:


If you see the proceeding window, congratulations, GLUT works for you!

Return

롯데라아에서....


마이크로소프트 진영이 Sun의 java로 시작해서 애플의 아이폰으로 물러난 것 같지만. 닷넷의 화려한 부활을 위해서 암암리에 손을 쓰고 있네요. WindowPhone7의 주개발환경을 .net으로 바꾸고, mono project ; http://www.mono-project.com/ 라는 것을 직접하지 않고 오픈소스 비슷한 조직을 이용해서 닷넷을 플렛폼독립적인 개발환경으로 이끌고 있네요. 이 모노 프로젝트는 마이크로소프트의 닷넷 개발환경으로 리눅스, 맥킨토시 응용 프로그램을 개발하는 것으로 이미 모노 자체가 일부 상용화 되어 있고, 볼랜드의 프리즘 (Delphi Prism)으로 상용화된 개발툴로 리눅스, 매킨토시의 응용 프로그램을 닷넷 프로그래밍으로 개발하게 하였습니다. 테스트 버전이 아닌 상용버전임은 이미 품질을 보증할 수 있다는 입장일 것이고, Window7의 정착으로 닷넷장착된 컴퓨터가 앞으로 대다수를 차지함에 따라, 마이크로소프트가 부활을 선언할 날이 머지 않았네요. 리눅스에서 닷넷으로 개발해보니 GUI개발환경이 너무 편리해진걸 느낄 수 있고, 매킨토시 프로그래밍도 다시 배우지 않아도 되어 차세대 Java이후 플랫폼 독립적 개발환경도 경쟁채제가 되겠습니다.

2010.11.30 하늘공원 나들이




2010.11.26 애플빠들 따라하기, IBM PC에 아이폰 및 매킨토시 개발환경 구축


[출처] http://www.cs.cf.ac.uk/Dave/C/node32.html

Subsections


Thread programming examples

This chapter gives some full code examples of thread programs. These examles are taken from a variety of sources:

  • The sun workshop developers web page http://www.sun.com/workshop/threads/share-code/ on threads is an excelleny source
  • The web page http://www.sun.com/workshop/threads/Berg-Lewis/examples.html where example from the Threads Primer Book by D. Berg anD B. Lewis are also a major resource.

Using thr_create() and thr_join()

This example exercises the thr_create() and thr_join() calls. There is not a parent/child relationship between threads as there is for processes. This can easily be seen in this example, because threads are created and joined by many different threads in the process. The example also shows how threads behave when created with different attributes and options.

Threads can be created by any thread and joined by any other.

The main thread: In this example the main thread's sole purpose is to create new threads. Threads A, B, and C are created by the main thread. Notice that thread B is created suspended. After creating the new threads, the main thread exits. Also notice that the main thread exited by calling thr_exit(). If the main thread had used the exit() call, the whole process would have exited. The main thread's exit status and resources are held until it is joined by thread C.

Thread A: The first thing thread A does after it is created is to create thread D. Thread A then simulates some processing and then exits, using thr_exit(). Notice that thread A was created with the THR_DETACHED flag, so thread A's resources will be immediately reclaimed upon its exit. There is no way for thread A's exit status to be collected by a thr_join() call.

Thread B: Thread B was created in a suspended state, so it is not able to run until thread D continues it by making the thr_continue() call. After thread B is continued, it simulates some processing and then exits. Thread B's exit status and thread resources are held until joined by thread E.

Thread C: The first thing that thread C does is to create thread F. Thread C then joins the main thread. This action will collect the main thread's exit status and allow the main thread's resources to be reused by another thread. Thread C will block, waiting for the main thread to exit, if the main thread has not yet called thr_exit(). After joining the main thread, thread C will simulate some processing and then exit. Again, the exit status and thread resources are held until joined by thread E.

Thread D: Thread D immediately creates thread E. After creating thread E, thread D continues thread B by making the thr_continue() call. This call will allow thread B to start its execution. Thread D then tries to join thread E, blocking until thread E has exited. Thread D then simulates some processing and exits. If all went well, thread D should be the last nondaemon thread running. When thread D exits, it should do two things: stop the execution of any daemon threads and stop the execution of the process.

Thread E: Thread E starts by joining two threads, threads B and C. Thread E will block, waiting for each of these thread to exit. Thread E will then simulate some processing and will exit. Thread E's exit status and thread resources are held by the operating system until joined by thread D.

Thread F: Thread F was created as a bound, daemon thread by using the THR_BOUND and THR_DAEMON flags in the thr_create() call. This means that it will run on its own LWP until all the nondaemon threads have exited the process. This type of thread can be used when you want some type of "background" processing to always be running, except when all the "regular" threads have exited the process. If thread F was created as a non-daemon thread, then it would continue to run forever, because a process will continue while there is at least one thread still running. Thread F will exit when all the nondaemon threads have exited. In this case, thread D should be the last nondaemon thread running, so when thread D exits, it will also cause thread F to exit.

This example, however trivial, shows how threads behave differently, based on their creation options. It also shows what happens on the exit of a thread, again based on how it was created. If you understand this example and how it flows, you should have a good understanding of how to use thr_create() and thr_join() in your own programs. Hopefully you can also see how easy it is to create and join threads.

The source to multi_thr.c:

#define _REENTRANT#include <stdio.h>#include <thread.h>/* Function prototypes for thread routines */void *sub_a(void *);void *sub_b(void *);void *sub_c(void *);void *sub_d(void *);void *sub_e(void *);void *sub_f(void *);thread_t thr_a, thr_b, thr_c;void main(){thread_t main_thr;main_thr = thr_self();printf("Main thread = %d\n", main_thr); if (thr_create(NULL, 0, sub_b, NULL, THR_SUSPENDED|THR_NEW_LWP, &thr_b))        fprintf(stderr,"Can't create thr_b\n"), exit(1);if (thr_create(NULL, 0, sub_a, (void *)thr_b, THR_NEW_LWP, &thr_a))        fprintf(stderr,"Can't create thr_a\n"), exit(1);if (thr_create(NULL, 0, sub_c, (void *)main_thr, THR_NEW_LWP, &thr_c))        fprintf(stderr,"Can't create thr_c\n"), exit(1);printf("Main Created threads A:%d B:%d C:%d\n", thr_a, thr_b, thr_c); printf("Main Thread exiting...\n"); thr_exit((void *)main_thr);}void *sub_a(void *arg){thread_t thr_b = (thread_t) arg;thread_t thr_d;int i;printf("A: In thread A...\n"); if (thr_create(NULL, 0, sub_d, (void *)thr_b, THR_NEW_LWP, &thr_d))        fprintf(stderr, "Can't create thr_d\n"), exit(1);printf("A: Created thread D:%d\n", thr_d); /* process */for (i=0;i<1000000*(int)thr_self();i++);printf("A: Thread exiting...\n"); thr_exit((void *)77);}void * sub_b(void *arg){int i;printf("B: In thread B...\n"); /* process */for (i=0;i<1000000*(int)thr_self();i++);printf("B: Thread exiting...\n"); thr_exit((void *)66);}void * sub_c(void *arg){void *status;int i;thread_t main_thr, ret_thr;main_thr = (thread_t)arg;printf("C: In thread C...\n"); if (thr_create(NULL, 0, sub_f, (void *)0, THR_BOUND|THR_DAEMON, NULL))        fprintf(stderr, "Can't create thr_f\n"), exit(1);printf("C: Join main thread\n"); if (thr_join(main_thr,(thread_t *)&ret_thr, &status))         fprintf(stderr, "thr_join Error\n"), exit(1);printf("C: Main thread (%d) returned thread (%d) w/status %d\n", main_thr, ret_thr, (int) status); /* process */for (i=0;i<1000000*(int)thr_self();i++);printf("C: Thread exiting...\n"); thr_exit((void *)88);}void * sub_d(void *arg){thread_t thr_b = (thread_t) arg;int i;thread_t thr_e, ret_thr;void *status;printf("D: In thread D...\n"); if (thr_create(NULL, 0, sub_e, NULL, THR_NEW_LWP, &thr_e))        fprintf(stderr,"Can't create thr_e\n"), exit(1);printf("D: Created thread E:%d\n", thr_e); printf("D: Continue B thread = %d\n", thr_b); thr_continue(thr_b);printf("D: Join E thread\n"); if(thr_join(thr_e,(thread_t *)&ret_thr, &status))         fprintf(stderr,"thr_join Error\n"), exit(1);printf("D: E thread (%d) returned thread (%d) w/status %d\n", thr_e, ret_thr, (int) status); /* process */for (i=0;i<1000000*(int)thr_self();i++);printf("D: Thread exiting...\n"); thr_exit((void *)55);}void * sub_e(void *arg){int i;thread_t ret_thr;void *status;printf("E: In thread E...\n"); printf("E: Join A thread\n"); if(thr_join(thr_a,(thread_t *)&ret_thr, &status))         fprintf(stderr,"thr_join Error\n"), exit(1);printf("E: A thread (%d) returned thread (%d) w/status %d\n", ret_thr, ret_thr, (int) status); printf("E: Join B thread\n"); if(thr_join(thr_b,(thread_t *)&ret_thr, &status))         fprintf(stderr,"thr_join Error\n"), exit(1);printf("E: B thread (%d) returned thread (%d) w/status %d\n", thr_b, ret_thr, (int) status); printf("E: Join C thread\n"); if(thr_join(thr_c,(thread_t *)&ret_thr, &status))         fprintf(stderr,"thr_join Error\n"), exit(1);printf("E: C thread (%d) returned thread (%d) w/status %d\n", thr_c, ret_thr, (int) status); for (i=0;i<1000000*(int)thr_self();i++);printf("E: Thread exiting...\n"); thr_exit((void *)44);}void *sub_f(void *arg){int i;printf("F: In thread F...\n"); while (1) {        for (i=0;i<10000000;i++);        printf("F: Thread F is still running...\n");         }}

Arrays

This example uses a data structure that contains multiple arrays of data. Multiple threads will concurrently vie for access to the arrays. To control this access, a mutex variable is used within the data structure to lock the entire array and serialize the access to the data.

The main thread first initializes the data structure and the mutex variable. It then sets a level of concurrency and creates the worker threads. The main thread then blocks by joining all the threads. When all the threads have exited, the main thread prints the results.

The worker threads modify the shared data structure from within a loop. Each time the threads need to modify the shared data, they lock the mutex variable associated with the shared data. After modifying the data, the threads unlock the mutex, allowing another thread access to the data.

This example may look quite simple, but it shows how important it is to control access to a simple, shared data structure. The results can be quite different if the mutex variable is not used.

The source to array.c:

#define _REENTRANT#include <stdio.h>#include <thread.h>/* sample array data structure */struct {        mutex_t data_lock[5];        int     int_val[5];        float   float_val[5];        } Data;/* thread function */void *Add_to_Value();main(){int i;/* initialize the mutexes and data */for (i=0; i<5; i++) {        mutex_init(&Data.data_lock[i], USYNC_THREAD, 0);        Data.int_val[i] = 0;        Data.float_val[i] = 0;        }/* set concurrency and create the threads */thr_setconcurrency(4);for (i=0; i<5; i++)    thr_create(NULL, 0, Add_to_Value, (void *)(2*i), 0, NULL);/* wait till all threads have finished */for (i=0; i<5; i++)        thr_join(0,0,0);/* print the results */printf("Final Values.....\n");for (i=0; i<5; i++) {        printf("integer value[%d] =\t%d\n", i, Data.int_val[i]);        printf("float value[%d] =\t%.0f\n\n", i, Data.float_val[i]);        }return(0);}/* Threaded routine */void *Add_to_Value(void *arg){int inval = (int) arg;int i;for (i=0;i<10000;i++){    mutex_lock(&Data.data_lock[i%5]);       Data.int_val[i%5] += inval;       Data.float_val[i%5] += (float) 1.5 * inval;    mutex_unlock(&Data.data_lock[i%5]);    }return((void *)0);}

Deadlock

This example demonstrates how a deadlock can occur in multithreaded programs that use synchronization variables. In this example a thread is created that continually adds a value to a global variable. The thread uses a mutex lock to protect the global data.

The main thread creates the counter thread and then loops, waiting for user input. When the user presses the Return key, the main thread suspends the counter thread and then prints the value of the global variable. The main thread prints the value of the global variable under the protection of a mutex lock.

The problem arises in this example when the main thread suspends the counter thread while the counter thread is holding the mutex lock. After the main thread suspends the counter thread, it tries to lock the mutex variable. Since the mutex variable is already held by the counter thread, which is suspended, the main thread deadlocks.

This example may run fine for a while, as long as the counter thread just happens to be suspended when it is not holding the mutex lock. The example demonstrates how tricky some programming issues can be when you deal with threads.

The source to susp_lock.c

#define _REENTRANT#include <stdio.h>#include <thread.h>/* Prototype for thread subroutine */void *counter(void *);int count;mutex_t count_lock;main(){char str[80];thread_t ctid;/* create the thread counter subroutine */thr_create(NULL, 0, counter, 0, THR_NEW_LWP|THR_DETACHED, &ctid);while(1) {        gets(str);        thr_suspend(ctid);        mutex_lock(&count_lock);        printf("\n\nCOUNT = %d\n\n", count);        mutex_unlock(&count_lock);        thr_continue(ctid);        }return(0);}void *counter(void *arg){int i;while (1) {        printf("."); fflush(stdout);        mutex_lock(&count_lock);        count++;        for (i=0;i<50000;i++);        mutex_unlock(&count_lock);        for (i=0;i<50000;i++);        }return((void *)0);}

Signal Handler

This example shows how easy it is to handle signals in multithreaded programs. In most programs, a different signal handler would be needed to service each type of signal that you wanted to catch. Writing each of the signal handlers can be time consuming and can be a real pain to debug.

This example shows how you can implement a signal handler thread that will service all asynchronous signals that are sent to your process. This is an easy way to deal with signals, because only one thread is needed to handle all the signals. It also makes it easy when you create new threads within the process, because you need not worry about signals in any of the threads.

First, in the main thread, mask out all signals and then create a signal handling thread. Since threads inherit the signal mask from their creator, any new threads created after the new signal mask will also mask all signals. This idea is key, because the only thread that will receive signals is the one thread that does not block all the signals.

The signal handler thread waits for all incoming signals with the sigwait() call. This call unmasks the signals given to it and then blocks until a signal arrives. When a signal arrives, sigwait() masks the signals again and then returns with the signal ID of the incoming signal.

You can extend this example for use in your application code to handle all your signals. Notice also that this signal concept could be added in your existing nonthreaded code as a simpler way to deal with signals.

The source to thr_sig.c

#define _REENTRANT#include <stdio.h>#include <thread.h>#include <signal.h>#include <sys/types.h>void *signal_hand(void *);main(){sigset_t set;/* block all signals in main thread.  Any other threads that are   created after this will also block all signals */sigfillset(&set); thr_sigsetmask(SIG_SETMASK, &set, NULL);/* create a signal handler thread.  This thread will catch all   signals and decide what to do with them.  This will only   catch nondirected signals.  (I.e., if a thread causes a SIGFPE    then that thread will get that signal. */thr_create(NULL, 0, signal_hand, 0, THR_NEW_LWP|THR_DAEMON|THR_DETACHED, NULL);while (1) {	/*	Do your normal processing here....	*/	}  /* end of while */return(0);}void *signal_hand(void *arg){sigset_t set;int sig;sigfillset(&set); /* catch all signals */while (1) { 	/* wait for a signal to arrive */	switch (sig=sigwait(&set)) {	  /* here you would add whatever signal you needed to catch */	  case SIGINT : {			printf("Interrupted with signal %d, exiting...\n", sig);			exit(0); 			}	  default : printf("GOT A SIGNAL = %d\n", sig); 	  } /* end of switch */	} /* end of while */return((void *)0);} /* end of signal_hand */

Another example of a signal handler, sig_kill.c:

/**  Multithreaded Demo Source* *  Copyright (C) 1995 by Sun Microsystems, Inc.*  All rights reserved.* *  This file is a product of SunSoft, Inc. and is provided for*  unrestricted use provided that this legend is included on all*  media and as a part of the software program in whole or part.*  Users may copy, modify or distribute this file at will.* *  THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING*  THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR*  PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.* *  This file is provided with no support and without any obligation on the*  part of SunSoft, Inc. to assist in its use, correction, modification or*  enhancement.* *  SUNSOFT AND SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT*  TO THE INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS*  FILE OR ANY PART THEREOF.* *  IN NO EVENT WILL SUNSOFT OR SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY*  LOST REVENUE OR PROFITS OR OTHER SPECIAL, INDIRECT AND CONSEQUENTIAL*  DAMAGES, EVEN IF THEY HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH*  DAMAGES.* *  SunSoft, Inc.*  2550 Garcia Avenue*  Mountain View, California  94043*//*  * Rich Schiavi writes:  		Sept 11, 1994 * * I believe the recommended way to kill certain threads is * using a signal handler which then will exit that particular * thread properly. I'm not sure the exact reason (I can't remember), but * if you take out the signal_handler routine in my example, you will see what * you describe, as the main process dies even if you send the * thr_kill to the specific thread. * I whipped up a real quick simple example which shows this using * some sleep()s to get a good simulation. */#include <stdio.h>#include <thread.h>#include <signal.h>static	thread_t 	one_tid, two_tid, main_thread;static 	void	*first_thread();static 	void	*second_thread();void		ExitHandler(int);static	mutex_t	    	first_mutex, second_mutex;int 	first_active = 1 ; int	second_active = 1;main(){  int i;  struct sigaction act;  act.sa_handler = ExitHandler;  (void) sigemptyset(&act.sa_mask);  (void) sigaction(SIGTERM, &act, NULL);   mutex_init(&first_mutex, 0 , 0);  mutex_init(&second_mutex, 0 , 0);  main_thread = thr_self();  thr_create(NULL,0,first_thread,0,THR_NEW_LWP,&one_tid);  thr_create(NULL,0,second_thread,0,THR_NEW_LWP,&two_tid);   for (i = 0; i < 10; i++){    fprintf(stderr, "main loop: %d\n", i);    if (i == 5)	{      thr_kill(one_tid, SIGTERM);    }    sleep(3);  }  thr_kill(two_tid, SIGTERM);  sleep(5);  fprintf(stderr, "main exit\n");}static void *first_thread(){  int i = 0;   fprintf(stderr, "first_thread id: %d\n", thr_self());  while (first_active){    fprintf(stderr, "first_thread: %d\n", i++);	    sleep(2);  }  fprintf(stderr, "first_thread exit\n");}static void *second_thread(){  int i = 0;  fprintf(stderr, "second_thread id: %d\n", thr_self());  while (second_active){    fprintf(stderr, "second_thread: %d\n", i++);    sleep(3);  }  fprintf(stderr, "second_thread exit\n");}void ExitHandler(int sig){  thread_t id;  id = thr_self();  fprintf(stderr, "ExitHandler thread id: %d\n", id);  thr_exit(0);}

Interprocess Synchronization

This example uses some of the synchronization variables available in the threads library to synchronize access to a resource shared between two processes. The synchronization variables used in the threads library are an advantage over standard IPC synchronization mechanisms because of their speed. The synchronization variables in the threads libraries have been tuned to be very lightweight and very fast. This speed can be an advantage when your application is spending time synchronizing between processes.

This example shows how semaphores from the threads library can be used between processes. Note that this program does not use threads; it is just using the lightweight semaphores available from the threads library.

When using synchronization variables between processes, it is important to make sure that only one process initializes the variable. If both processes try to initialize the synchronization variable, then one of the processes will overwrite the state of the variable set by the other process.

The source to ipc.c

#include <stdio.h>#include <fcntl.h>#include <sys/mman.h>#include <synch.h>#include <sys/types.h>#include <unistd.h>/* a structure that will be used between processes */typedef struct {	sema_t mysema;	int num;} buf_t;main(){int 	i, j, fd;buf_t 	*buf;/* open a file to use in a memory mapping */fd = open("/dev/zero", O_RDWR);/* create a shared memory map with the open file for the data    structure that will be shared between processes */buf=(buf_t *)mmap(NULL, sizeof(buf_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);/* initialize the semaphore -- note the USYNC_PROCESS flag; this makes   the semaphore visible from a process level */sema_init(&buf->mysema, 0, USYNC_PROCESS, 0);/* fork a new process */if (fork() == 0) {	/* The child will run this section of code */	for (j=0;j<5;j++)		{		/* have the child "wait" for the semaphore */		printf("Child PID(%d): waiting...\n", getpid());		sema_wait(&buf->mysema);		/* the child decremented the semaphore */		printf("Child PID(%d): decrement semaphore.\n", getpid());		}	/* exit the child process */ 	printf("Child PID(%d): exiting...\n", getpid());	exit(0);	}/* The parent will run this section of code *//* give the child a chance to start running */sleep(2);for (i=0;i<5;i++)	{	/* increment (post) the semaphore */	printf("Parent PID(%d): posting semaphore.\n", getpid());	sema_post(&buf->mysema);	/* wait a second */	sleep(1);	}/* exit the parent process */printf("Parent PID(%d): exiting...\n", getpid());return(0);}

The Producer / Consumer Problem

This example will show how condition variables can be used to control access of reads and writes to a buffer. This example can also be thought as a producer/consumer problem, where the producer adds items to the buffer and the consumer removes items from the buffer.

Two condition variables control access to the buffer. One condition variable is used to tell if the buffer is full, and the other is used to tell if the buffer is empty. When the producer wants to add an item to the buffer, it checks to see if the buffer is full; if it is full the producer blocks on the cond_wait() call, waiting for an item to be removed from the buffer. When the consumer removes an item from the buffer, the buffer is no longer full, so the producer is awakened from the cond_wait() call. The producer is then allowed to add another item to the buffer.

The consumer works, in many ways, the same as the producer. The consumer uses the other condition variable to determine if the buffer is empty. When the consumer wants to remove an item from the buffer, it checks to see if it is empty. If the buffer is empty, the consumer then blocks on the cond_wait() call, waiting for an item to be added to the buffer. When the producer adds an item to the buffer, the consumer's condition is satisfied, so it can then remove an item from the buffer.

The example copies a file by reading data into a shared buffer (producer) and then writing data out to the new file (consumer). The Buf data structure is used to hold both the buffered data and the condition variables that control the flow of the data.

The main thread opens both files, initializes the Buf data structure, creates the consumer thread, and then assumes the role of the producer. The producer reads data from the input file, then places the data into an open buffer position. If no buffer positions are available, then the producer waits via the cond_wait() call. After the producer has read all the data from the input file, it closes the file and waits for (joins) the consumer thread.

The consumer thread reads from a shared buffer and then writes the data to the output file. If no buffers positions are available, then the consumer waits for the producer to fill a buffer position. After the consumer has read all the data, it closes the output file and exits.

If the input file and the output file were residing on different physical disks, then this example could execute the reads and writes in parallel. This parallelism would significantly increase the throughput of the example through the use of threads.

The source to prod_cons.c:

#define _REEENTRANT#include <stdio.h>#include <thread.h>#include <fcntl.h>#include <unistd.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/uio.h>#define BUFSIZE 512#define BUFCNT  4/* this is the data structure that is used between the producer   and consumer threads */struct {        char buffer[BUFCNT][BUFSIZE];        int byteinbuf[BUFCNT];        mutex_t buflock;        mutex_t donelock;        cond_t adddata;        cond_t remdata;        int nextadd, nextrem, occ, done;} Buf;/* function prototype */void *consumer(void *);main(int argc, char **argv){int ifd, ofd;thread_t cons_thr;/* check the command line arguments */if (argc != 3)        printf("Usage: %s <infile> <outfile>\n", argv[0]), exit(0);/* open the input file for the producer to use */if ((ifd = open(argv[1], O_RDONLY)) == -1)        {        fprintf(stderr, "Can't open file %s\n", argv[1]);        exit(1);        }/* open the output file for the consumer to use */if ((ofd = open(argv[2], O_WRONLY|O_CREAT, 0666)) == -1)        {        fprintf(stderr, "Can't open file %s\n", argv[2]);        exit(1);        }/* zero the counters */Buf.nextadd = Buf.nextrem = Buf.occ = Buf.done = 0;/* set the thread concurrency to 2 so the producer and consumer can   run concurrently */thr_setconcurrency(2);/* create the consumer thread */thr_create(NULL, 0, consumer, (void *)ofd, NULL, &cons_thr);/* the producer ! */while (1) {        /* lock the mutex */        mutex_lock(&Buf.buflock);        /* check to see if any buffers are empty */        /* If not then wait for that condition to become true */        while (Buf.occ == BUFCNT)                cond_wait(&Buf.remdata, &Buf.buflock);        /* read from the file and put data into a buffer */        Buf.byteinbuf[Buf.nextadd] = read(ifd,Buf.buffer[Buf.nextadd],BUFSIZE);        /* check to see if done reading */        if (Buf.byteinbuf[Buf.nextadd] == 0) {                /* lock the done lock */                mutex_lock(&Buf.donelock);                /* set the done flag and release the mutex lock */                Buf.done = 1;                mutex_unlock(&Buf.donelock);                /* signal the consumer to start consuming */                cond_signal(&Buf.adddata);                /* release the buffer mutex */                mutex_unlock(&Buf.buflock);                /* leave the while looop */                break;                }        /* set the next buffer to fill */        Buf.nextadd = ++Buf.nextadd % BUFCNT;        /* increment the number of buffers that are filled */        Buf.occ++;        /* signal the consumer to start consuming */        cond_signal(&Buf.adddata);        /* release the mutex */        mutex_unlock(&Buf.buflock);        }close(ifd);/* wait for the consumer to finish */thr_join(cons_thr, 0, NULL);/* exit the program */return(0);}/* The consumer thread */void *consumer(void *arg){int fd = (int) arg;/* check to see if any buffers are filled or if the done flag is set */while (1) {        /* lock the mutex */        mutex_lock(&Buf.buflock);        if (!Buf.occ && Buf.done) {           mutex_unlock(&Buf.buflock);           break;           }        /* check to see if any buffers are filled */        /* if not then wait for the condition to become true */        while (Buf.occ == 0 && !Buf.done)                cond_wait(&Buf.adddata, &Buf.buflock);        /* write the data from the buffer to the file */        write(fd, Buf.buffer[Buf.nextrem], Buf.byteinbuf[Buf.nextrem]);        /* set the next buffer to write from */        Buf.nextrem = ++Buf.nextrem % BUFCNT;        /* decrement the number of buffers that are full */        Buf.occ--;        /* signal the producer that a buffer is empty */        cond_signal(&Buf.remdata);        /* release the mutex */        mutex_unlock(&Buf.buflock);        }/* exit the thread */thr_exit((void *)0);}

A Socket Server

The socket server example uses threads to implement a "standard" socket port server. The example shows how easy it is to use thr_create() calls in the place of fork() calls in existing programs.

A standard socket server should listen on a socket port and, when a message arrives, fork a process to service the request. Since a fork() system call would be used in a nonthreaded program, any communication between the parent and child would have to be done through some sort of interprocess communication.

We can replace the fork() call with a thr_create() call. Doing so offers a few advantages: thr_create() can create a thread much faster then a fork() could create a new process, and any communication between the server and the new thread can be done with common variables. This technique makes the implementation of the socket server much easier to understand and should also make it respond much faster to incoming requests.

The server program first sets up all the needed socket information. This is the basic setup for most socket servers. The server then enters an endless loop, waiting to service a socket port. When a message is sent to the socket port, the server wakes up and creates a new thread to handle the request. Notice that the server creates the new thread as a detached thread and also passes the socket descriptor as an argument to the new thread.

The newly created thread can then read or write, in any fashion it wants, to the socket descriptor that was passed to it. At this point the server could be creating a new thread or waiting for the next message to arrive. The key is that the server thread does not care what happens to the new thread after it creates it.

In our example, the created thread reads from the socket descriptor and then increments a global variable. This global variable keeps track of the number of requests that were made to the server. Notice that a mutex lock is used to protect access to the shared global variable. The lock is needed because many threads might try to increment the same variable at the same time. The mutex lock provides serial access to the shared variable. See how easy it is to share information among the new threads! If each of the threads were a process, then a significant effort would have to be made to share this information among the processes.

The client piece of the example sends a given number of messages to the server. This client code could also be run from different machines by multiple users, thus increasing the need for concurrency in the server process.

The source code to soc_server.c:

#define _REENTRANT#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <string.h>#include <sys/uio.h>#include <unistd.h>#include <thread.h>/* the TCP port that is used for this example */#define TCP_PORT   6500/* function prototypes and global variables */void *do_chld(void *);mutex_t lock;int	service_count;main(){	int 	sockfd, newsockfd, clilen;	struct sockaddr_in cli_addr, serv_addr;	thread_t chld_thr;	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)		fprintf(stderr,"server: can't open stream socket\n"), exit(0);	memset((char *) &serv_addr, 0, sizeof(serv_addr));	serv_addr.sin_family = AF_INET;	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);	serv_addr.sin_port = htons(TCP_PORT);		if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)		fprintf(stderr,"server: can't bind local address\n"), exit(0);	/* set the level of thread concurrency we desire */	thr_setconcurrency(5);	listen(sockfd, 5);	for(;;){		clilen = sizeof(cli_addr);		newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);		if(newsockfd < 0)			fprintf(stderr,"server: accept error\n"), exit(0);		/* create a new thread to process the incomming request */		thr_create(NULL, 0, do_chld, (void *) newsockfd, THR_DETACHED, &chld_thr);		/* the server is now free to accept another socket request */		}	return(0);}/* 	This is the routine that is executed from a new thread */void *do_chld(void *arg){int 	mysocfd = (int) arg;char 	data[100];int 	i;	printf("Child thread [%d]: Socket number = %d\n", thr_self(), mysocfd);	/* read from the given socket */	read(mysocfd, data, 40);	printf("Child thread [%d]: My data = %s\n", thr_self(), data);	/* simulate some processing */	for (i=0;i<1000000*thr_self();i++);	printf("Child [%d]: Done Processing...\n", thr_self()); 	/* use a mutex to update the global service counter */	mutex_lock(&lock);	service_count++;	mutex_unlock(&lock);	printf("Child thread [%d]: The total sockets served = %d\n", thr_self(), service_count);	/* close the socket and exit this thread */	close(mysocfd);	thr_exit((void *)0);}

Using Many Threads

This example that shows how easy it is to create many threads of execution in Solaris. Because of the lightweight nature of threads, it is possible to create literally thousands of threads. Most applications may not need a very large number of threads, but this example shows just how lightweight the threads can be.

We have said before that anything you can do with threads, you can do without them. This may be a case where it would be very hard to do without threads. If you have some spare time (and lots of memory), try implementing this program by using processes, instead of threads. If you try this, you will see why threads can have an advantage over processes.

This program takes as an argument the number of threads to create. Notice that all the threads are created with a user-defined stack size, which limits the amount of memory that the threads will need for execution. The stack size for a given thread can be hard to calculate, so some testing usually needs to be done to see if the chosen stack size will work. You may want to change the stack size in this program and see how much you can lower it before things stop working. The Solaris threads library provides the thr_min_stack() call, which returns the minimum allowed stack size. Take care when adjusting the size of a threads stack. A stack overflow can happen quite easily to a thread with a small stack.

After each thread is created, it blocks, waiting on a mutex variable. This mutex variable was locked before any of the threads were created, which prevents the threads from proceeding in their execution. When all of the threads have been created and the user presses Return, the mutex variable is unlocked, allowing all the threads to proceed.

After the main thread has created all the threads, it waits for user input and then tries to join all the threads. Notice that the thr_join() call does not care what thread it joins; it is just counting the number of joins it makes.

This example is rather trivial and does not serve any real purpose except to show that it is possible to create a lot of threads in one process. However, there are situations when many threads are needed in an application. An example might be a network port server, where a thread is created each time an incoming or outgoing request is made.

The source to many_thr.c:

#define _REENTRANT#include <stdio.h>#include <stdlib.h>#include <thread.h>/* function prototypes and global varaibles */void *thr_sub(void *);mutex_t lock;main(int argc, char **argv){int i, thr_count = 100;char buf;/* check to see if user passed an argument   -- if so, set the number of threads to the value      passed to the program */if (argc == 2) thr_count = atoi(argv[1]);printf("Creating %d threads...\n", thr_count);/* lock the mutex variable -- this mutex is being used to    keep all the other threads created from proceeding   */mutex_lock(&lock);/* create all the threads -- Note that a specific stack size is   given.  Since the created threads will not use all of the   default stack size, we can save memory by reducing the threads'   stack size */for (i=0;i<thr_count;i++) {	thr_create(NULL,2048,thr_sub,0,0,NULL);	}printf("%d threads have been created and are running!\n", i);printf("Press <return> to join all the threads...\n", i);/* wait till user presses return, then join all the threads */gets(&buf);printf("Joining %d threads...\n", thr_count);/* now unlock the mutex variable, to let all the threads proceed */mutex_unlock(&lock);/* join the threads */for (i=0;i<thr_count;i++) 	thr_join(0,0,0);printf("All %d threads have been joined, exiting...\n", thr_count);return(0);}/* The routine that is executed by the created threads */void *thr_sub(void *arg){/* try to lock the mutex variable -- since the main thread has   locked the mutex before the threads were created, this thread   will block until the main thread unlock the mutex */mutex_lock(&lock);printf("Thread %d is exiting...\n", thr_self());/* unlock the mutex to allow another thread to proceed */mutex_unlock(&lock);/* exit the thread */return((void *)0);}

Real-time Thread Example

This example uses the Solaris real-time extensions to make a single bound thread within a process run in the real-time scheduling class. Using a thread in the real-time class is more desirable than running a whole process in the real-time class, because of the many problems that can arise with a process in a real-time state. For example, it would not be desirable for a process to perform any I/O or large memory operations while in realtime, because a real-time process has priority over system-related processes; if a real-time process requests a page fault, it can starve, waiting for the system to fault in a new page. We can limit this exposure by using threads to execute only the instructions that need to run in realtime.

Since this book does not cover the concerns that arise with real-time programming, we have included this code only as an example of how to promote a thread into the real-time class. You must be very careful when you use real-time threads in your applications. For more information on real-time programming, see the Solaris  documentation.

This example should be safe from the pitfalls of real-time programs because of its simplicity. However, changing this code in any way could have adverse affects on your system.

The example creates a new thread from the main thread. This new thread is then promoted to the real-time class by looking up the real-time class ID and then setting a real-time priority for the thread. After the thread is running in realtime, it simulates some processing. Since a thread in the real-time class can have an infinite time quantum, the process is allowed to stay on a CPU as long as it likes. The time quantum is the amount of time a thread is allowed to stay running on a CPU. For the timesharing class, the time quantum (time-slice) is 1/100th of a second by default.

In this example, we set the time quantum for the real-time thread to infinity. That is, it can stay running as long as it likes; it will not be preempted or scheduled off the CPU. If you run this example on a UP machine, it will have the effect of stopping your system for a few seconds while the thread simulates its processing. The system does not actually stop, it is just working in the real-time thread. When the real-time thread finishes its processing, it exits and the system returns to normal.

Using real-time threads can be quite useful when you need an extremely high priority and response time but can also cause big problems if it not used properly. Also note that this example must be run as root or have root execute permissions.

The source to rt_thr.c:

#define _REENTRANT#include <stdio.h>#include <thread.h>#include <string.h>#include <sys/priocntl.h>#include <sys/rtpriocntl.h>/* thread prototype */void *rt_thread(void *);main(){/* create the thread that will run in realtime */thr_create(NULL, 0, rt_thread, 0, THR_DETACHED, 0);/* loop here forever, this thread is the TS scheduling class */while (1) {	printf("MAIN: In time share class... running\n"); 	sleep(1);	}return(0);}/*	This is the routine that is called by the created thread*/void *rt_thread(void *arg){pcinfo_t pcinfo;pcparms_t pcparms;int i;/* let the main thread run for a bit */sleep(4);/* get the class ID for the real-time class */strcpy(pcinfo.pc_clname, "RT");if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)	fprintf(stderr, "getting RT class id\n"), exit(1);/* set up the real-time parameters */pcparms.pc_cid = pcinfo.pc_cid;((rtparms_t *)pcparms.pc_clparms)->rt_pri = 10;((rtparms_t *)pcparms.pc_clparms)->rt_tqnsecs = 0;/* set an infinite time quantum */((rtparms_t *)pcparms.pc_clparms)->rt_tqsecs = RT_TQINF; /* move this thread to the real-time scheduling class */if (priocntl(P_LWPID, P_MYID, PC_SETPARMS, (caddr_t)&pcparms) == -1)	fprintf(stderr, "Setting RT mode\n"), exit(1);/* simulate some processing */for (i=0;i<100000000;i++);printf("RT_THREAD: NOW EXITING...\n");thr_exit((void *)0);}

POSIX Cancellation

This example uses the POSIX thread cancellation capability to kill a thread that is no longer needed. Random termination of a thread can cause problems in threaded applications, because a thread may be holding a critical lock when it is terminated. Since the lock was help before the thread was terminated, another thread may deadlock, waiting for that same lock. The thread cancellation capability enables you to control when a thread can be terminated. The example also demonstrates the capabilities of the POSIX thread library in implementing a program that performs a multithreaded search.

This example simulates a multithreaded search for a given number by taking random guesses at a target number. The intent here is to simulate the same type of search that a database might execute. For example, a database might create threads to start searching for a data item; after some amount of time, one or more threads might return with the target data item.

If a thread guesses the number correctly, there is no need for the other threads to continue their search. This is where thread cancellation can help. The thread that finds the number first should cancel the other threads that are still searching for the item and then return the results of the search.

The threads involved in the search can call a cleanup function that can clean up the threads resources before it exits. In this case, the cleanup function prints the progress of the thread when it was cancelled.

The source to posix_cancel.c:

 #define _REENTRANT#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <pthread.h>/* defines the number of searching threads */#define NUM_THREADS 25/* function prototypes */void *search(void *);void print_it(void *);/* global variables */pthread_t  threads[NUM_THREADS];pthread_mutex_t lock;int tries;main(){int i;int pid;/* create a number to search for */pid = getpid();/* initialize the mutex lock */pthread_mutex_init(&lock, NULL); printf("Searching for the number = %d...\n", pid);/* create the searching threads */for (i=0;i<NUM_THREADS;i++)	pthread_create(&threads[i], NULL, search, (void *)pid);/* wait for (join) all the searching threads */for (i=0;i<NUM_THREADS;i++) 	pthread_join(threads[i], NULL);printf("It took %d tries to find the number.\n", tries);/* exit this thread */pthread_exit((void *)0);}/*	This is the cleanup function that is called when 	the threads are cancelled */void print_it(void *arg){int *try = (int *) arg;pthread_t tid;/* get the calling thread's ID */tid = pthread_self();/* print where the thread was in its search when it was cancelled */printf("Thread %d was canceled on its %d try.\n", tid, *try); }/*	This is the search routine that is executed in each thread */void *search(void *arg){int num = (int) arg;int i=0, j;pthread_t tid;/* get the calling thread ID */tid = pthread_self();/* use the thread ID to set the seed for the random number generator */srand(tid);/* set the cancellation parameters --   - Enable thread cancellation    - Defer the action of the cancellation */pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);/* push the cleanup routine (print_it) onto the thread   cleanup stack.  This routine will be called when the    thread is cancelled.  Also note that the pthread_cleanup_push   call must have a matching pthread_cleanup_pop call.  The   push and pop calls MUST be at the same lexical level    within the code *//* pass address of `i' since the current value of `i' is not    the one we want to use in the cleanup function */pthread_cleanup_push(print_it, (void *)&i);/* loop forever */while (1) {	i++;	/* does the random number match the target number? */	if (num == rand()) {		/* try to lock the mutex lock --                   if locked, check to see if the thread has been cancelled		   if not locked then continue */		while (pthread_mutex_trylock(&lock) == EBUSY)				pthread_testcancel();		/* set the global variable for the number of tries */	   	tries = i;	   	printf("thread %d found the number!\n", tid);		/* cancel all the other threads */	   	for (j=0;j<NUM_THREADS;j++) 			if (threads[j] != tid) pthread_cancel(threads[j]);		/* break out of the while loop */		break;	  	}	/* every 100 tries check to see if the thread has been cancelled            if the thread has not been cancelled then yield the thread's	   LWP to another thread that may be able to run */	if (i%100 == 0) {		pthread_testcancel();		sched_yield();		}	}/* The only way we can get here is when the thread breaks out   of the while loop.  In this case the thread that makes it here   has found the number we are looking for and does not need to run   the thread cleanup function.  This is why the pthread_cleanup_pop   function is called with a 0 argument; this will pop the cleanup   function off the stack without executing it */pthread_cleanup_pop(0);return((void *)0);}

Software Race Condition

This example shows a trivial software race condition. A software race condition occurs when the execution of a program is affected by the order and timing of a threads execution. Most software race conditions can be alleviated by using synchronization variables to control the threads' timing and access of shared resources. If a program depends on order of execution, then threading that program may not be a good solution, because the order in which threads execute is nondeterministic.

In the example, thr_continue() and thr_suspend() calls continue and suspend a given thread, respectively. Although both of these calls are valid, use caution when implementing them. It is very hard to determine where a thread is in its execution. Because of this, you may not be able to tell where the thread will suspend when the call to thr_suspend() is made. This behavior can cause problems in threaded code if not used properly.

The following example uses thr_continue() and thr_suspend() to try to control when a thread starts and stops. The example looks trivial, but, as you will see, can cause a big problem.

Do you see the problem? If you guessed that the program would eventually suspend itself, you were correct! The example attempts to flip-flop between the main thread and a subroutine thread. Each thread continues the other thread and then suspends itself.

Thread A continues thread B and then suspends thread A; now the continued thread B can continue thread A and then suspend itself. This should continue back and forth all day long, right? Wrong! We can't guarantee that each thread will continue the other thread and then suspend itself in one atomic action, so a software race condition could be created. Calling thr_continue() on a running thread and calling thr_suspend() on a suspended thread has no effect, so we don't know if a thread is already running or suspended.

If thread A continues thread B and if between the time thread A suspends itself, thread B continues thread A, then both of the threads will call thr_suspend(). This is the race condition in this program that will cause the whole process to become suspended.

It is very hard to use these calls, because you never really know the state of a thread. If you don't know exactly where a thread is in its execution, then you don't know what locks it holds and where it will stop when you suspend it.

The source to sw_race.c

Tgrep: Threadeds version of UNIX grep

Tgrep is a multi-threaded version of grep. Tgrep supports all but the -w (word search) options of the normal grep command, and a few options that are only avaliable to Tgrep. The real change from grep, is that Tgrep will recurse down through sub-directories and search all files for the target string. Tgrep searches files like the following command:

find <start path> -name "<file/directory pattern>" -exec \ (Line wrapped)        grep <options> <target> /dev/null {} \;

An example of this would be (run from this Tgrep directory)

% find . -exec grep thr_create /dev/null {} \;./Solaris/main.c:  if (thr_create(NULL,0,SigThread,NULL,THR_DAEMON,NULL)) {./Solaris/main.c:          err = thr_create(NULL,0,cascade,(void *)work,./Solaris/main.c:           err = thr_create(NULL,0,search_thr,(void *)work,%Running the same command with timex: real        4.26user        0.64sys         2.81

The same search run with Tgrep would be

% {\tt Tgrep} thr_create./Solaris/main.c:  if (thr_create(NULL,0,SigThread,NULL,THR_DAEMON,NULL)) {./Solaris/main.c:          err = thr_create(NULL,0,cascade,(void *)work,./Solaris/main.c:           err = thr_create(NULL,0,search_thr,(void *)work,%Running the same command with timex:real        0.79user        0.62sys         1.50

Tgrep gets the results almost four times faster. The numbers above where gathered on a SS20 running 5.5 (build 18) with 4 50MHz CPUs.

You can also filter the files that you want Tgrep to search like you can with find. The next two commands do the same thing, just Tgrep gets it done faster.

find . -name "*.c" -exec grep thr_create /dev/null {} \;and{\tt Tgrep} -p '.*\.c$' thr_create

The -p option will allow Tgrep to search only files that match the "regular expression" file pattern string. This option does NOT use shell expression, so to stop Tgrep from seeing a file named foobar.cyou must add the "$" meta character to the pattern and escape the real ``.'' character.

Some of the other Tgrep only options are -r, -C, -P, -e, -B, -S and -Z. The -r option stops Tgrep from searching any sub-directories, in other words, search only the local directory, but -l was taken. The -C option will search for and print "continued" lines like you find in Makefile. Note the differences in the results of grep and Tgrep run in the current directory.

The Tgrep output prints the continued lines that ended with the "character. In the case of grep I would not have seen the three values assigned to SUBDIRS, but Tgrep shows them to me (Common, Solaris, Posix).

The -P option I use when I am sending the output of a long search to a file and want to see the "progress" of the search. The -P option will print a "." (dot) on stderr for every file (or groups of files depending on the value of the -P argument) Tgrep searches.

The -e option will change the way Tgrep uses the target string. Tgrep uses two different patter matching systems. The first (with out the -e option) is a literal string match call Boyer-Moore. If the -e option is used, then a MT-Safe PD version of regular expression is used to search for the target string as a regexp with meta characters in it. The regular expression method is slower, but Tgrep needed the functionality. The -Z option will print help on the meta characters Tgrep uses.

The -B option tells Tgrep to use the value of the environment variable called TGLIMIT to limit the number of threads it will use during a search. This option has no affect if TGLIMIT is not set. Tgrep can "eat" a system alive, so the -B option was a way to run Tgrep on a system with out having other users scream at you.

The last new option is -S. If you want to see how things went while Tgrep was searching, you can use this option to print statistic about the number of files, lines, bytes, matches, threads created, etc.

Here is an example of the -S options output. (again run in the current directory)

% {\tt Tgrep} -S zimzap----------------- {\tt Tgrep} Stats. --------------------Number of directories searched:           7Number of files searched:                 37Number of lines searched:                 9504Number of matching lines to target:       0Number of cascade threads created:        7Number of search threads created:         20Number of search threads from pool:       17Search thread pool hit rate:              45.95%Search pool overall size:                 20Search pool size limit:                   58Number of search threads destroyed:       0Max # of threads running concurrenly:     20Total run time, in seconds.               1Work stopped due to no FD's:  (058)       0 Times, 0.00%Work stopped due to no work on Q:         19 Times, 43.18%Work stopped due to TGLIMITS: (Unlimited) 0 Times, 0.00%----------------------------------------------------%

For more information on the usage and options, see the man page Tgrep

The Tgrep.c source code is:

/* Copyright (c) 1993, 1994  Ron Winacott                               *//* This program may be used, copied, modified, and redistributed freely *//* for ANY purpose, so long as this notice remains intact.              */#define _REENTRANT#include <stdio.h>#include <string.h>#include <stdlib.h> #include <unistd.h>#include <assert.h>#include <errno.h>#include <signal.h>#include <ctype.h> #include <sys/types.h>#include <time.h>#include <sys/stat.h>#ifdef __sparc#include <note.h> /* warlock/locklint */#else#define NOTE(s) #endif#include <dirent.h>#include <fcntl.h>#include <sys/uio.h>#include <thread.h> #include <synch.h>#include "version.h"#include "pmatch.h"#include "debug.h" #define PATH_MAX		1024 /* max # of characters in a path name */#define HOLD_FDS                6  /* stdin,out,err and a buffer */#define UNLIMITED               99999 /* The default tglimit */#define MAXREGEXP               10  /* max number of -e options */#define FB_BLOCK                0x00001#define FC_COUNT                0x00002#define FH_HOLDNAME             0x00004#define FI_IGNCASE              0x00008#define FL_NAMEONLY             0x00010#define FN_NUMBER               0x00020#define FS_NOERROR              0x00040#define FV_REVERSE              0x00080#define FW_WORD                 0x00100#define FR_RECUR                0x00200#define FU_UNSORT               0x00400#define FX_STDIN                0x00800#define TG_BATCH                0x01000#define TG_FILEPAT              0x02000#define FE_REGEXP               0x04000#define FS_STATS                0x08000#define FC_LINE                 0x10000#define TG_PROGRESS             0x20000#define FILET                   1#define DIRT                    2#define ALPHASIZ        	128/* * New data types  */typedef struct work_st {    char                *path;    int                 tp;    struct work_st      *next;} work_t;typedef struct out_st {    char                *line;    int                 line_count;    long                byte_count;    struct out_st       *next;} out_t;typedef struct bm_pattern {     /* Boyer - Moore pattern                */        short            p_m;           /* length of pattern string     */        short            p_r[ALPHASIZ]; /* "r" vector                   */        short           *p_R;           /* "R" vector                   */        char            *p_pat;         /* pattern string               */} BM_PATTERN;/* * Prototypes *//* bmpmatch.c */extern BM_PATTERN *bm_makepat(char *);extern char *bm_pmatch(BM_PATTERN *, register char *);extern void bm_freepat(BM_PATTERN *);/* pmatch.c */extern char *pmatch(register PATTERN *, register char *, int *);extern PATTERN *makepat(char *string, char *);extern void freepat(register PATTERN *);extern void printpat(PATTERN *);#include "proto.h"  /* function prototypes of main.c */void *SigThread(void *arg);void sig_print_stats(void);/* * Global data */BM_PATTERN      *bm_pat;  /* the global target read only after main */NOTE(READ_ONLY_DATA(bm_pat))PATTERN         *pm_pat[MAXREGEXP];  /* global targets read only for pmatch */NOTE(READ_ONLY_DATA(pm_pat))mutex_t global_count_lk; int     global_count = 0;NOTE(MUTEX_PROTECTS_DATA(global_count_lk, global_count))NOTE(DATA_READABLE_WITHOUT_LOCK(global_count))  /* see prnt_stats() */work_t  *work_q = NULL;cond_t  work_q_cv;mutex_t work_q_lk;int     all_done = 0;int     work_cnt = 0;int     current_open_files = 0;int     tglimit = UNLIMITED;    /* if -B limit the number of threads */NOTE(MUTEX_PROTECTS_DATA(work_q_lk, work_q all_done work_cnt \			 current_open_files tglimit))work_t  *search_q = NULL;mutex_t search_q_lk;cond_t  search_q_cv;int     search_pool_cnt = 0;    /* the count in the pool now */int     search_thr_limit = 0;   /* the max in the pool */NOTE(MUTEX_PROTECTS_DATA(search_q_lk, search_q search_pool_cnt))NOTE(DATA_READABLE_WITHOUT_LOCK(search_pool_cnt)) /* see prnt_stats() */NOTE(READ_ONLY_DATA(search_thr_limit))work_t	*cascade_q = NULL;mutex_t cascade_q_lk;cond_t  cascade_q_cv;int	cascade_pool_cnt = 0;int     cascade_thr_limit = 0;NOTE(MUTEX_PROTECTS_DATA(cascade_q_lk, cascade_q cascade_pool_cnt))NOTE(DATA_READABLE_WITHOUT_LOCK(cascade_pool_cnt))  /* see prnt_stats() */NOTE(READ_ONLY_DATA(cascade_thr_limit))int     running = 0;mutex_t running_lk;NOTE(MUTEX_PROTECTS_DATA(running_lk, running))sigset_t set, oldset;NOTE(READ_ONLY_DATA(set oldset))mutex_t stat_lk;time_t  st_start = 0;int     st_dir_search = 0;int     st_file_search = 0;int     st_line_search = 0;int     st_cascade = 0;int	st_cascade_pool = 0;int     st_cascade_destroy = 0;int     st_search = 0;int     st_pool = 0;int     st_maxrun = 0;int     st_worknull = 0;int     st_workfds = 0;int     st_worklimit = 0;int     st_destroy = 0;NOTE(MUTEX_PROTECTS_DATA(stat_lk, st_start st_dir_search st_file_search \			 st_line_search st_cascade st_cascade_pool \			 st_cascade_destroy st_search st_pool st_maxrun \			 st_worknull st_workfds st_worklimit st_destroy))int     progress_offset = 1;NOTE(READ_ONLY_DATA(progress_offset))mutex_t output_print_lk;/* output_print_lk used to print multi-line output only */int     progress = 0;NOTE(MUTEX_PROTECTS_DATA(output_print_lk, progress))unsigned int    flags = 0;int     regexp_cnt = 0;char    *string[MAXREGEXP];int     debug = 0;int     use_pmatch = 0;char    file_pat[255];  /* file patten match */PATTERN *pm_file_pat; /* compiled file target string (pmatch()) */NOTE(READ_ONLY_DATA(flags regexp_cnt string debug use_pmatch \		    file_pat pm_file_pat))/* * Locking ording. */NOTE(LOCK_ORDER(output_print_lk stat_lk))/* * Main: This is where the fun starts */intmain(int argc, char **argv){    int         c,out_thr_flags;    long        max_open_files = 0l, ncpus = 0l;    extern int  optind;    extern char *optarg;    NOTE(READ_ONLY_DATA(optind optarg))    int         prio = 0;    struct stat sbuf;    thread_t    tid,dtid;    void        *status;    char        *e = NULL, *d = NULL; /* for debug flags */    int         debug_file = 0;    int         err = 0, i = 0, pm_file_len = 0;    work_t      *work;    int         restart_cnt = 10;    flags = FR_RECUR;  /* the default */    thr_setprio(thr_self(),127);  /* set me up HIGH */    while ((c = getopt(argc, argv, "d:e:bchilnsvwruf:p:BCSZzHP:")) != EOF) {        switch (c) {#ifdef DEBUG                case 'd':            debug = atoi(optarg);            if (debug == 0)                debug_usage();            d = optarg;            fprintf(stderr,"tgrep: Debug on at level(s) ");            while (*d) {                for (i=0; i<9; i++)                    if (debug_set[i].level == *d) {                        debug_levels |= debug_set[i].flag;                        fprintf(stderr,"%c ",debug_set[i].level);                        break;                    }                d++;            }            fprintf(stderr,"\n");            break;        case 'f': 	    debug_file = atoi(optarg); 	    break;#endif      /* DEBUG */        case 'B':            flags |= TG_BATCH;	    if ((e = getenv("TGLIMIT"))) {		tglimit = atoi(e);	    }	    else {		if (!(flags & FS_NOERROR))  /* order dependent! */		    fprintf(stderr,"env TGLIMIT not set, overriding -B\n");		flags &= ~TG_BATCH;	    }            break;        case 'p':            flags |= TG_FILEPAT;            strcpy(file_pat,optarg);            pm_file_pat = makepat(file_pat,NULL);             break;        case 'P':            flags |= TG_PROGRESS;            progress_offset = atoi(optarg);            break;        case 'S': flags |= FS_STATS;    break;        case 'b': flags |= FB_BLOCK;    break;        case 'c': flags |= FC_COUNT;    break;        case 'h': flags |= FH_HOLDNAME; break;        case 'i': flags |= FI_IGNCASE;  break;        case 'l': flags |= FL_NAMEONLY; break;        case 'n': flags |= FN_NUMBER;   break;        case 's': flags |= FS_NOERROR;  break;        case 'v': flags |= FV_REVERSE;  break;        case 'w': flags |= FW_WORD;     break;        case 'r': flags &= ~FR_RECUR;   break;        case 'C': flags |= FC_LINE;     break;        case 'e':            if (regexp_cnt == MAXREGEXP) {                fprintf(stderr,"Max number of regexp's (%d) exceeded!\n",                        MAXREGEXP);                exit(1);            }            flags |= FE_REGEXP;            if ((string[regexp_cnt] =(char *)malloc(strlen(optarg)+1))==NULL){                fprintf(stderr,"tgrep: No space for search string(s)\n");                exit(1);            }            memset(string[regexp_cnt],0,strlen(optarg)+1);            strcpy(string[regexp_cnt],optarg);             regexp_cnt++;            break;        case 'z':        case 'Z': regexp_usage();            break;        case 'H':        case '?':        default : usage();        }    }    if (!(flags & FE_REGEXP)) {       if (argc - optind < 1) {            fprintf(stderr,"tgrep: Must supply a search string(s) "                    "and file list or directory\n");            usage();        }        if ((string[0]=(char *)malloc(strlen(argv[optind])+1))==NULL){            fprintf(stderr,"tgrep: No space for search string(s)\n");            exit(1);        }        memset(string[0],0,strlen(argv[optind])+1);        strcpy(string[0],argv[optind]);        regexp_cnt=1;        optind++;    }    if (flags & FI_IGNCASE)        for (i=0; i<regexp_cnt; i++)            uncase(string[i]);#ifdef __lock_lint    /*     ** This is NOT somthing you really want to do. This    ** function calls are here ONLY for warlock/locklint !!!    */    pm_pat[i] = makepat(string[i],NULL);    bm_pat = bm_makepat(string[0]);    bm_freepat(bm_pat);  /* stop it from becomming a root */#else    if (flags & FE_REGEXP) {        for (i=0; i<regexp_cnt; i++)            pm_pat[i] = makepat(string[i],NULL);        use_pmatch = 1;    }    else {        bm_pat = bm_makepat(string[0]); /* only one allowed */    }#endif        flags |= FX_STDIN;    max_open_files = sysconf(_SC_OPEN_MAX);    ncpus = sysconf(_SC_NPROCESSORS_ONLN);    if ((max_open_files - HOLD_FDS - debug_file) < 1) {        fprintf(stderr,"tgrep: You MUST have at lest ONE fd "                "that can be used, check limit (>10)\n");        exit(1);    }    search_thr_limit = max_open_files - HOLD_FDS - debug_file;    cascade_thr_limit = search_thr_limit / 2;    /* the number of files that can by open */    current_open_files = search_thr_limit;     mutex_init(&stat_lk,USYNC_THREAD,"stat");    mutex_init(&global_count_lk,USYNC_THREAD,"global_cnt");    mutex_init(&output_print_lk,USYNC_THREAD,"output_print");    mutex_init(&work_q_lk,USYNC_THREAD,"work_q");    mutex_init(&running_lk,USYNC_THREAD,"running");    cond_init(&work_q_cv,USYNC_THREAD,"work_q");    mutex_init(&search_q_lk,USYNC_THREAD,"search_q");    cond_init(&search_q_cv,USYNC_THREAD,"search_q");    mutex_init(&cascade_q_lk,USYNC_THREAD,"cascade_q");    cond_init(&cascade_q_cv,USYNC_THREAD,"cascade_q");    if ((argc == optind) && ((flags & TG_FILEPAT) || (flags & FR_RECUR))) {        add_work(".",DIRT);        flags = (flags & ~FX_STDIN);    }    for ( ; optind < argc; optind++) {        restart_cnt = 10;        flags = (flags & ~FX_STDIN);      STAT_AGAIN:        if (stat(argv[optind], &sbuf)) {            if (errno == EINTR) { /* try again !, restart */                if (--restart_cnt)                    goto STAT_AGAIN;            }            if (!(flags & FS_NOERROR))                fprintf(stderr,"tgrep: Can't stat file/dir %s, %s\n",                         argv[optind], strerror(errno));                     continue;        }        switch (sbuf.st_mode & S_IFMT) {        case S_IFREG :            if (flags & TG_FILEPAT) {                if (pmatch(pm_file_pat, argv[optind], &pm_file_len))		    add_work(argv[optind],FILET);            }            else {                add_work(argv[optind],FILET);            }            break;        case S_IFDIR :            if (flags & FR_RECUR) {                add_work(argv[optind],DIRT);            }            else {                if (!(flags & FS_NOERROR))                    fprintf(stderr,"tgrep: Can't search directory %s, "                            "-r option is on. Directory ignored.\n",                            argv[optind]);            }            break;        }    }     NOTE(COMPETING_THREADS_NOW)  /* we are goinf threaded */    if (flags & FS_STATS) {	mutex_lock(&stat_lk);        st_start = time(NULL);	mutex_unlock(&stat_lk);#ifdef SIGNAL_HAND	/* 	** setup the signal thread so the first call to SIGINT will 	** only print stats, the second will interupt.	*/	sigfillset(&set);	thr_sigsetmask(SIG_SETMASK, &set, &oldset);	if (thr_create(NULL,0,SigThread,NULL,THR_DAEMON,NULL)) {	    thr_sigsetmask(SIG_SETMASK,&oldset,NULL);	    fprintf(stderr,"SIGINT for stats NOT setup\n");	}	thr_yield(); /* give the other thread time */#endif /* SIGNAL_HAND */    }    thr_setconcurrency(3);    if (flags & FX_STDIN) {        fprintf(stderr,"tgrep: stdin option is not coded at this time\n");        exit(0);                        /* XXX Need to fix this SOON */        search_thr(NULL);  /* NULL is not understood in search_thr() */        if (flags & FC_COUNT) {            mutex_lock(&global_count_lk);            printf("%d\n",global_count);            mutex_unlock(&global_count_lk);        }        if (flags & FS_STATS) {	    mutex_lock(&stat_lk);            prnt_stats();	    mutex_unlock(&stat_lk);	}        exit(0);    }    mutex_lock(&work_q_lk);    if (!work_q) {        if (!(flags & FS_NOERROR))            fprintf(stderr,"tgrep: No files to search.\n");        exit(0);    }    mutex_unlock(&work_q_lk);    DP(DLEVEL1,("Starting to loop through the work_q for work\n"));        /* OTHER THREADS ARE RUNNING */    while (1) {        mutex_lock(&work_q_lk);        while ((work_q == NULL || current_open_files == 0 || tglimit <= 0) &&                all_done == 0) {            if (flags & FS_STATS) {                mutex_lock(&stat_lk);                if (work_q == NULL)                    st_worknull++;                if (current_open_files == 0)                    st_workfds++;                if (tglimit <= 0)                    st_worklimit++;                mutex_unlock(&stat_lk);            }            cond_wait(&work_q_cv,&work_q_lk);        }        if (all_done != 0) {            mutex_unlock(&work_q_lk);            DP(DLEVEL1,("All_done was set to TRUE\n"));            goto OUT;        }        work = work_q;        work_q = work->next;  /* maybe NULL */        work->next = NULL;        current_open_files--;        mutex_unlock(&work_q_lk);        tid = 0;        switch (work->tp) {        case DIRT:	    mutex_lock(&cascade_q_lk);	    if (cascade_pool_cnt) {		if (flags & FS_STATS) {                    mutex_lock(&stat_lk);                    st_cascade_pool++;                    mutex_unlock(&stat_lk);                }		work->next = cascade_q;		cascade_q = work;		cond_signal(&cascade_q_cv);                mutex_unlock(&cascade_q_lk);                DP(DLEVEL2,("Sent work to cascade pool thread\n"));	    }	    else {		mutex_unlock(&cascade_q_lk);		err = thr_create(NULL,0,cascade,(void *)work,				 THR_DETACHED|THR_DAEMON|THR_NEW_LWP				 ,&tid);		DP(DLEVEL2,("Sent work to new cascade thread\n"));		thr_setprio(tid,64);  /* set cascade to middle */		if (flags & FS_STATS) {		    mutex_lock(&stat_lk);		    st_cascade++;		    mutex_unlock(&stat_lk);		}	    }            break;        case FILET:            mutex_lock(&search_q_lk);            if (search_pool_cnt) {                if (flags & FS_STATS) {                    mutex_lock(&stat_lk);                    st_pool++;                    mutex_unlock(&stat_lk);                }                work->next = search_q;  /* could be null */                search_q = work;                cond_signal(&search_q_cv);                mutex_unlock(&search_q_lk);                DP(DLEVEL2,("Sent work to search pool thread\n"));            }            else {                mutex_unlock(&search_q_lk);                err = thr_create(NULL,0,search_thr,(void *)work,                                 THR_DETACHED|THR_DAEMON|THR_NEW_LWP                                 ,&tid);                thr_setprio(tid,0);  /* set search to low */                DP(DLEVEL2,("Sent work to new search thread\n"));                if (flags & FS_STATS) {                    mutex_lock(&stat_lk);                    st_search++;                    mutex_unlock(&stat_lk);                }            }            break;        default:            fprintf(stderr,"tgrep: Internal error, work_t->tp no valid\n");            exit(1);        }        if (err) {  /* NEED TO FIX THIS CODE. Exiting is just wrong */            fprintf(stderr,"Cound not create new thread!\n");            exit(1);        }    } OUT:    if (flags & TG_PROGRESS) {        if (progress)            fprintf(stderr,".\n");        else            fprintf(stderr,"\n");    }    /* we are done, print the stuff. All other threads ar parked */    if (flags & FC_COUNT) {        mutex_lock(&global_count_lk);        printf("%d\n",global_count);        mutex_unlock(&global_count_lk);    }    if (flags & FS_STATS)        prnt_stats();    return(0); /* should have a return from main */}/* * Add_Work: Called from the main thread, and cascade threads to add file  * and directory names to the work Q. */intadd_work(char *path,int tp){    work_t      *wt,*ww,*wp;    if ((wt = (work_t *)malloc(sizeof(work_t))) == NULL)        goto ERROR;         if ((wt->path = (char *)malloc(strlen(path)+1)) == NULL)        goto ERROR;        strcpy(wt->path,path);    wt->tp = tp;    wt->next = NULL;    if (flags & FS_STATS) {        mutex_lock(&stat_lk);        if (wt->tp == DIRT)            st_dir_search++;        else            st_file_search++;        mutex_unlock(&stat_lk);    }    mutex_lock(&work_q_lk);    work_cnt++;    wt->next = work_q;    work_q = wt;    cond_signal(&work_q_cv);    mutex_unlock(&work_q_lk);    return(0); ERROR:    if (!(flags & FS_NOERROR))        fprintf(stderr,"tgrep: Could not add %s to work queue. Ignored\n",                path);    return(-1);}/* * Search thread: Started by the main thread when a file name is found * on the work Q to be serached. If all the needed resources are ready * a new search thread will be created. */void *search_thr(void *arg) /* work_t *arg */{        FILE        *fin;    char        fin_buf[(BUFSIZ*4)];  /* 4 Kbytes */    work_t      *wt,std;    int         line_count;    char        rline[128];    char        cline[128];    char        *line;    register char *p,*pp;    int            pm_len;    int         len = 0;    long        byte_count;    long        next_line;    int         show_line;  /* for the -v option */    register int slen,plen,i;    out_t       *out = NULL;    /* this threads output list */    thr_setprio(thr_self(),0);  /* set search to low */    thr_yield();    wt = (work_t *)arg; /* first pass, wt is passed to use. */    /* len = strlen(string);*/  /* only set on first pass */        while (1) {  /* reuse the search threads */        /* init all back to zero */        line_count = 0;        byte_count = 0l;        next_line = 0l;        show_line = 0;        mutex_lock(&running_lk);        running++;        mutex_unlock(&running_lk);        mutex_lock(&work_q_lk);        tglimit--;        mutex_unlock(&work_q_lk);        DP(DLEVEL5,("searching file (STDIO) %s\n",wt->path));        if ((fin = fopen(wt->path,"r")) == NULL) {            if (!(flags & FS_NOERROR)) {                fprintf(stderr,"tgrep: %s. File \"%s\" not searched.\n",                        strerror(errno),wt->path);            }            goto ERROR;        }        setvbuf(fin,fin_buf,_IOFBF,(BUFSIZ*4));  /* XXX */        DP(DLEVEL5,("Search thread has opened file %s\n",wt->path));        while ((fgets(rline,127,fin)) != NULL) {            if (flags & FS_STATS) {                mutex_lock(&stat_lk);                st_line_search++;                mutex_unlock(&stat_lk);            }            slen = strlen(rline);            next_line += slen;              line_count++;            if (rline[slen-1] == '\n')                rline[slen-1] = '\0';            /*            ** If the uncase flag is set, copy the read in line (rline)            ** To the uncase line (cline) Set the line pointer to point at            ** cline.            ** If the case flag is NOT set, then point line at rline.            ** line is what is compared, rline is waht is printed on a             ** match.            */            if (flags & FI_IGNCASE) {                strcpy(cline,rline);                uncase(cline);                line = cline;            }            else {                line = rline;            }            show_line = 1;  /* assume no match, if -v set */            /* The old code removed */            if (use_pmatch) {                for (i=0; i<regexp_cnt; i++) {                    if (pmatch(pm_pat[i], line, &pm_len)) {                        if (!(flags & FV_REVERSE)) {                            add_output_local(&out,wt,line_count,                                             byte_count,rline);                            continue_line(rline,fin,out,wt,                                          &line_count,&byte_count);                        }                        else {                            show_line = 0;                         } /* end of if -v flag if / else block */                        /*                         ** if we get here on ANY of the regexp targets                        ** jump out of the loop, we found a single                        ** match so, do not keep looking!                        ** If name only, do not keep searcthing the same 			** file, we found a single match, so close the file, 			** print the file name and move on to the next file.                        */                        if (flags & FL_NAMEONLY)                             goto OUT_OF_LOOP;                        else                            goto OUT_AND_DONE;                    } /* end found a match if block */                } /* end of the for pat[s] loop */            }            else {                if (bm_pmatch( bm_pat, line)) {                    if (!(flags & FV_REVERSE)) {                        add_output_local(&out,wt,line_count,byte_count,rline);                        continue_line(rline,fin,out,wt,                                      &line_count,&byte_count);                    }                    else {                        show_line = 0;                     }                    if (flags & FL_NAMEONLY)                         goto OUT_OF_LOOP;                }            }          OUT_AND_DONE:            if ((flags & FV_REVERSE) && show_line) {                 add_output_local(&out,wt,line_count,byte_count,rline);                show_line = 0;            }            byte_count = next_line;        }      OUT_OF_LOOP:        fclose(fin);        /*        ** The search part is done, but before we give back the FD,        ** and park this thread in the search thread pool, print the        ** local output we have gathered.        */        print_local_output(out,wt);  /* this also frees out nodes */        out = NULL; /* for the next time around, if there is one */    ERROR:        DP(DLEVEL5,("Search done for %s\n",wt->path));        free(wt->path);        free(wt);        notrun();        mutex_lock(&search_q_lk);        if (search_pool_cnt > search_thr_limit) {            mutex_unlock(&search_q_lk);            DP(DLEVEL5,("Search thread exiting\n"));            if (flags & FS_STATS) {                mutex_lock(&stat_lk);                st_destroy++;                mutex_unlock(&stat_lk);            }            return(0);        }        else {            search_pool_cnt++;            while (!search_q)                cond_wait(&search_q_cv,&search_q_lk);            search_pool_cnt--;            wt = search_q;  /* we have work to do! */            if (search_q->next)                search_q = search_q->next;            else                search_q = NULL;            mutex_unlock(&search_q_lk);        }    }    /*NOTREACHED*/}/* * Continue line: Speacial case search with the -C flag set. If you are  * searching files like Makefiles, some lines may have escape char's to * contine the line on the next line. So the target string can be found, but  * no data is displayed. This function continues to print the escaped line * until there are no more "\" chars found. */intcontinue_line(char *rline, FILE *fin, out_t *out, work_t *wt, 	      int *lc, long *bc){    int len;    int cnt = 0;    char *line;    char nline[128];    if (!(flags & FC_LINE))        return(0);    line = rline;  AGAIN:    len = strlen(line);    if (line[len-1] == '\\') {        if ((fgets(nline,127,fin)) == NULL) {            return(cnt);        }        line = nline;        len = strlen(line);        if (line[len-1] == '\n')            line[len-1] = '\0';        *bc = *bc + len;        *lc++;        add_output_local(&out,wt,*lc,*bc,line);        cnt++;        goto AGAIN;    }    return(cnt);}/* * cascade: This thread is started by the main thread when directory names * are found on the work Q. The thread reads all the new file, and directory * names from the directory it was started when and adds the names to the  * work Q. (it finds more work!) */void *cascade(void *arg)  /* work_t *arg */{    char        fullpath[1025];    int         restart_cnt = 10;    DIR         *dp;    char        dir_buf[sizeof(struct dirent) + PATH_MAX];    struct dirent *dent = (struct dirent *)dir_buf;    struct stat   sbuf;    char        *fpath;    work_t      *wt;    int         fl = 0, dl = 0;    int         pm_file_len = 0;    thr_setprio(thr_self(),64);  /* set search to middle */    thr_yield();  /* try toi give control back to main thread */    wt = (work_t *)arg;    while(1) {	fl = 0;	dl = 0;	restart_cnt = 10;	pm_file_len = 0;	mutex_lock(&running_lk);	running++;	mutex_unlock(&running_lk);	mutex_lock(&work_q_lk);	tglimit--;	mutex_unlock(&work_q_lk);	if (!wt) {	    if (!(flags & FS_NOERROR))		fprintf(stderr,"tgrep: Bad work node passed to cascade\n");	    goto DONE;	}	fpath = (char *)wt->path;	if (!fpath) {	    if (!(flags & FS_NOERROR))		fprintf(stderr,"tgrep: Bad path name passed to cascade\n");	    goto DONE;	}	DP(DLEVEL3,("Cascading on %s\n",fpath));	if (( dp = opendir(fpath)) == NULL) {	    if (!(flags & FS_NOERROR))		fprintf(stderr,"tgrep: Can't open dir %s, %s. Ignored.\n",			fpath,strerror(errno));	    goto DONE;	}	while ((readdir_r(dp,dent)) != NULL) {	    restart_cnt = 10;  /* only try to restart the interupted 10 X */	    	    if (dent->d_name[0] == '.') {		if (dent->d_name[1] == '.' && dent->d_name[2] == '\0') 		    continue;		if (dent->d_name[1] == '\0')		    continue;	    }	    fl = strlen(fpath);	    dl = strlen(dent->d_name);	    if ((fl + 1 + dl) > 1024) {		fprintf(stderr,"tgrep: Path %s/%s is too long. "			"MaxPath = 1024\n",			fpath, dent->d_name);		continue;  /* try the next name in this directory */	    }	    strcpy(fullpath,fpath);	    strcat(fullpath,"/");	    strcat(fullpath,dent->d_name);	  RESTART_STAT:	    if (stat(fullpath,&sbuf)) {		if (errno == EINTR) {		    if (--restart_cnt)			goto RESTART_STAT;		}		if (!(flags & FS_NOERROR))		    fprintf(stderr,"tgrep: Can't stat file/dir %s, %s. "			    "Ignored.\n",			    fullpath,strerror(errno));		goto ERROR;	    }	    switch (sbuf.st_mode & S_IFMT) {	    case S_IFREG :		if (flags & TG_FILEPAT) {		    if (pmatch(pm_file_pat, dent->d_name, &pm_file_len)) {			DP(DLEVEL3,("file pat match (cascade) %s\n",				    dent->d_name));			add_work(fullpath,FILET);		    }		}		else {		    add_work(fullpath,FILET);		    DP(DLEVEL3,("cascade added file (MATCH) %s to Work Q\n",				fullpath));		}		break;	    case S_IFDIR :		DP(DLEVEL3,("cascade added dir %s to Work Q\n",fullpath));		add_work(fullpath,DIRT);		break;	    }	}      ERROR:	closedir(dp);      DONE:	free(wt->path);	free(wt);	notrun();	mutex_lock(&cascade_q_lk);	if (cascade_pool_cnt > cascade_thr_limit) {	    mutex_unlock(&cascade_q_lk);	    DP(DLEVEL5,("Cascade thread exiting\n"));	    if (flags & FS_STATS) {		mutex_lock(&stat_lk);		st_cascade_destroy++;		mutex_unlock(&stat_lk);	    }	    return(0); /* thr_exit */	}	else {	    DP(DLEVEL5,("Cascade thread waiting in pool\n"));	    cascade_pool_cnt++;	    while (!cascade_q)		cond_wait(&cascade_q_cv,&cascade_q_lk);	    cascade_pool_cnt--;	    wt = cascade_q;  /* we have work to do! */	    if (cascade_q->next)		cascade_q = cascade_q->next;	    else		cascade_q = NULL;	    mutex_unlock(&cascade_q_lk);	}    }    /*NOTREACHED*/}/* * Print Local Output: Called by the search thread after it is done searching * a single file. If any oputput was saved (matching lines), the lines are  * displayed as a group on stdout.  */intprint_local_output(out_t *out, work_t *wt){    out_t       *pp, *op;    int         out_count = 0;    int         printed = 0;    int 	print_name = 1;    pp = out;    mutex_lock(&output_print_lk);    if (pp && (flags & TG_PROGRESS)) {        progress++;        if (progress >= progress_offset) {            progress = 0;            fprintf(stderr,".");        }    }    while (pp) {	out_count++;	if (!(flags & FC_COUNT)) {	    if (flags & FL_NAMEONLY) {  /* Pint name ONLY ! */		if (!printed) {		    printed = 1;		    printf("%s\n",wt->path);		}	    }	    else {  /* We are printing more then just the name */		if (!(flags & FH_HOLDNAME))  /* do not print name ? */		    printf("%s :",wt->path);		if (flags & FB_BLOCK)		    printf("%ld:",pp->byte_count/512+1);		if (flags & FN_NUMBER)		    printf("%d:",pp->line_count);		printf("%s\n",pp->line);	    }	}        op = pp;        pp = pp->next;        /* free the nodes as we go down the list */        free(op->line);        free(op);    }    mutex_unlock(&output_print_lk);    mutex_lock(&global_count_lk);    global_count += out_count;    mutex_unlock(&global_count_lk);    return(0);}/* * add output local: is called by a search thread as it finds matching lines.  * the matching line, it's byte offset, line count, etc are stored until the * search thread is done searching the file, then the lines are printed as  * a group. This way the lines from more then a single file are not mixed * together. */intadd_output_local(out_t **out, work_t *wt,int lc, long bc, char *line){    out_t       *ot,*oo, *op;    if (( ot = (out_t *)malloc(sizeof(out_t))) == NULL)        goto ERROR;    if (( ot->line = (char *)malloc(strlen(line)+1)) == NULL)        goto ERROR;    strcpy(ot->line,line);    ot->line_count = lc;    ot->byte_count = bc;        if (!*out) {        *out = ot;        ot->next = NULL;        return(0);    }    /* append to the END of the list, keep things sorted! */    op = oo = *out;        while(oo) {        op = oo;        oo = oo->next;    }    op->next = ot;    ot->next = NULL;    return(0); ERROR:    if (!(flags & FS_NOERROR))        fprintf(stderr,"tgrep: Output lost. No space. "                "[%s: line %d byte %d match : %s\n",                wt->path,lc,bc,line);    return(1);}/* * print stats: If the -S flag is set, after ALL files have been searched,  * main thread calls this function to print the stats it keeps on how the * search went. */voidprnt_stats(void){    float a,b,c;    float t = 0.0;    time_t  st_end = 0;    char    tl[80];    st_end = time(NULL); /* stop the clock */    fprintf(stderr,"\n----------------- Tgrep Stats. --------------------\n");    fprintf(stderr,"Number of directories searched:           %d\n",	    st_dir_search);    fprintf(stderr,"Number of files searched:                 %d\n",	    st_file_search);    c = (float)(st_dir_search + st_file_search) / (float)(st_end - st_start);    fprintf(stderr,"Dir/files per second:                     %3.2f\n",	    c);    fprintf(stderr,"Number of lines searched:                 %d\n",	    st_line_search);    fprintf(stderr,"Number of matching lines to target:       %d\n",	    global_count);    fprintf(stderr,"Number of cascade threads created:        %d\n",	    st_cascade);    fprintf(stderr,"Number of cascade threads from pool:      %d\n",	    st_cascade_pool);    a = st_cascade_pool; b = st_dir_search;    fprintf(stderr,"Cascade thread pool hit rate:             %3.2f%%\n",	    ((a/b)*100));    fprintf(stderr,"Cascade pool overall size:                %d\n",	    cascade_pool_cnt);    fprintf(stderr,"Cascade pool size limit:                  %d\n",	    cascade_thr_limit);    fprintf(stderr,"Number of cascade threads destroyed:      %d\n",	    st_cascade_destroy);    fprintf(stderr,"Number of search threads created:         %d\n",	    st_search);    fprintf(stderr,"Number of search threads from pool:       %d\n",	    st_pool);    a = st_pool; b = st_file_search;    fprintf(stderr,"Search thread pool hit rate:              %3.2f%%\n",	    ((a/b)*100));    fprintf(stderr,"Search pool overall size:                 %d\n",	    search_pool_cnt);    fprintf(stderr,"Search pool size limit:                   %d\n",	    search_thr_limit);    fprintf(stderr,"Number of search threads destroyed:       %d\n",	    st_destroy);    fprintf(stderr,"Max # of threads running concurrenly:     %d\n",	    st_maxrun);    fprintf(stderr,"Total run time, in seconds.               %d\n",           (st_end - st_start));    /* Why did we wait ? */    a = st_workfds; b = st_dir_search+st_file_search;    c = (a/b)*100; t += c;    fprintf(stderr,"Work stopped due to no FD's:  (%.3d)       %d Times, %3.2f%%\n",           search_thr_limit,st_workfds,c);    a = st_worknull; b = st_dir_search+st_file_search;    c = (a/b)*100; t += c;    fprintf(stderr,"Work stopped due to no work on Q:         %d Times, %3.2f%%\n",           st_worknull,c);#ifndef __lock_lint  /* it is OK to read HERE with out the lock ! */    if (tglimit == UNLIMITED)        strcpy(tl,"Unlimited");    else        sprintf(tl,"   %.3d   ",tglimit);#endif    a = st_worklimit; b = st_dir_search+st_file_search;    c = (a/b)*100; t += c;    fprintf(stderr,"Work stopped due to TGLIMIT:  (%.9s) %d Times, %3.2f%%\n",           tl,st_worklimit,c);    fprintf(stderr,"Work continued to be handed out:          %3.2f%%\n",	    100.00-t);    fprintf(stderr,"----------------------------------------------------\n");}/* * not running: A glue function to track if any search threads or cascade  * threads are running. When the count is zero, and the work Q is NULL, * we can safly say, WE ARE DONE. */void notrun (void){    mutex_lock(&work_q_lk);    work_cnt--;    tglimit++;    current_open_files++;    mutex_lock(&running_lk);    if (flags & FS_STATS) {        mutex_lock(&stat_lk);        if (running > st_maxrun) {            st_maxrun = running;	    DP(DLEVEL6,("Max Running has increased to %d\n",st_maxrun));	}        mutex_unlock(&stat_lk);    }    running--;    if (work_cnt == 0 && running == 0) {        all_done = 1;        DP(DLEVEL6,("Setting ALL_DONE flag to TRUE.\n"));    }    mutex_unlock(&running_lk);    cond_signal(&work_q_cv);    mutex_unlock(&work_q_lk);}/* * uncase: A glue function. If the -i (case insensitive) flag is set, the * target strng and the read in line is converted to lower case before * comparing them. */voiduncase(char *s){    char        *p;    for (p = s; *p != NULL; p++)        *p = (char)tolower(*p);}/* * SigThread: if the -S option is set, the first ^C set to tgrep will * print the stats on the fly, the second will kill the process. */void *SigThread(void *arg){    int sig;    int stats_printed = 0;    while (1) {	sig = sigwait(&set);	DP(DLEVEL7,("Signal %d caught\n",sig));	switch (sig) {	case -1:	    fprintf(stderr,"Signal error\n");	    break;	case SIGINT:	    if (stats_printed)		exit(1);	    stats_printed = 1;	    sig_print_stats();	    break;	case SIGHUP:	    sig_print_stats();	    break;	default:	    DP(DLEVEL7,("Default action taken (exit) for signal %d\n",sig));	    exit(1);  /* default action */	}    }}voidsig_print_stats(void){    /*    ** Get the output lock first    ** Then get the stat lock.    */    mutex_lock(&output_print_lk);    mutex_lock(&stat_lk);    prnt_stats();    mutex_unlock(&stat_lk);    mutex_unlock(&output_print_lk);    return;}/* * usage: Have to have one of these. */void usage(void){    fprintf(stderr,"usage: tgrep <options> pattern <{file,dir}>...\n");    fprintf(stderr,"\n");    fprintf(stderr,"Where:\n");#ifdef DEBUG        fprintf(stderr,"Debug     -d = debug level -d <levels> (-d0 for usage)\n");    fprintf(stderr,"Debug     -f = block fd's from use (-f #)\n");#endif        fprintf(stderr,"          -b = show block count (512 byte block)\n");    fprintf(stderr,"          -c = print only a line count\n");    fprintf(stderr,"          -h = do not print file names\n");    fprintf(stderr,"          -i = case insensitive\n");    fprintf(stderr,"          -l = print file name only\n");    fprintf(stderr,"          -n = print the line number with the line\n");    fprintf(stderr,"          -s = Suppress error messages\n");    fprintf(stderr,"          -v = print all but matching lines\n");#ifdef NOT_IMP        fprintf(stderr,"          -w = search for a \"word\"\n");#endif        fprintf(stderr,"          -r = Do not search for files in all "                                "sub-directories\n");    fprintf(stderr,"          -C = show continued lines (\"\\\")\n");    fprintf(stderr,"          -p = File name regexp pattern. (Quote it)\n");    fprintf(stderr,"          -P = show progress. -P 1 prints a DOT on stderr\n"                   "               for each file it finds, -P 10 prints a DOT\n"                   "               on stderr for each 10 files it finds, etc...\n");    fprintf(stderr,"          -e = expression search.(regexp) More then one\n");    fprintf(stderr,"          -B = limit the number of threads to TGLIMIT\n");    fprintf(stderr,"          -S = Print thread stats when done.\n");    fprintf(stderr,"          -Z = Print help on the regexp used.\n");    fprintf(stderr,"\n");    fprintf(stderr,"Notes:\n");    fprintf(stderr,"      If you start tgrep with only a directory name\n");    fprintf(stderr,"      and no file names, you must not have the -r option\n");    fprintf(stderr,"      set or you will get no output.\n");    fprintf(stderr,"      To search stdin (piped input), you must set -r\n");    fprintf(stderr,"      Tgrep will search ALL files in ALL \n");    fprintf(stderr,"      sub-directories. (like */* */*/* */*/*/* etc..)\n");    fprintf(stderr,"      if you supply a directory name.\n");    fprintf(stderr,"      If you do not supply a file, or directory name,\n");    fprintf(stderr,"      and the -r option is not set, the current \n");    fprintf(stderr,"      directory \".\" will be used.\n");    fprintf(stderr,"      All the other options should work \"like\" grep\n");    fprintf(stderr,"      The -p patten is regexp, tgrep will search only\n");    fprintf(stderr,"      the file names that match the patten\n");    fprintf(stderr,"\n");    fprintf(stderr,"      Tgrep Version %s\n",Tgrep_Version);    fprintf(stderr,"\n");    fprintf(stderr,"      Copy Right By Ron Winacott, 1993-1995.\n");    fprintf(stderr,"\n");    exit(0);}/* * regexp usage: Tell the world about tgrep custom (THREAD SAFE) regexp! */int regexp_usage (void){    fprintf(stderr,"usage: tgrep <options> -e \"pattern\" <-e ...> "	    "<{file,dir}>...\n");    fprintf(stderr,"\n");    fprintf(stderr,"metachars:\n");    fprintf(stderr,"    . - match any character\n");    fprintf(stderr,"    * - match 0 or more occurrences of pervious char\n");    fprintf(stderr,"    + - match 1 or more occurrences of pervious char.\n");    fprintf(stderr,"    ^ - match at begining of string\n");    fprintf(stderr,"    $ - match end of string\n");    fprintf(stderr,"    [ - start of character class\n");    fprintf(stderr,"    ] - end of character class\n");    fprintf(stderr,"    ( - start of a new pattern\n");    fprintf(stderr,"    ) - end of a new pattern\n");    fprintf(stderr,"    @(n)c - match <c> at column <n>\n");    fprintf(stderr,"    | - match either pattern\n");    fprintf(stderr,"    \\ - escape any special characters\n");    fprintf(stderr,"    \\c - escape any special characters\n");    fprintf(stderr,"    \\o - turn on any special characters\n");    fprintf(stderr,"\n");    fprintf(stderr,"To match two diffrerent patterns in the same command\n");    fprintf(stderr,"Use the or function. \n"            "ie: tgrep -e \"(pat1)|(pat2)\" file\n"            "This will match any line with \"pat1\" or \"pat2\" in it.\n");    fprintf(stderr,"You can also use up to %d -e expresions\n",MAXREGEXP);    fprintf(stderr,"RegExp Pattern matching brought to you by Marc Staveley\n");    exit(0);}/* * debug usage: If compiled with -DDEBUG, turn it on, and tell the world * how to get tgrep to print debug info on different threads. */#ifdef DEBUGvoiddebug_usage(void){    int i = 0;    fprintf(stderr,"DEBUG usage and levels:\n");    fprintf(stderr,"--------------------------------------------------\n");    fprintf(stderr,"Level                   code\n");    fprintf(stderr,"--------------------------------------------------\n");    fprintf(stderr,"0                 This message.\n");    for (i=0; i<9; i++) {        fprintf(stderr,"%d                 %s\n",i+1,debug_set[i].name);    }    fprintf(stderr,"--------------------------------------------------\n");    fprintf(stderr,"You can or the levels together like -d134 for levels\n");    fprintf(stderr,"1 and 3 and 4.\n");    fprintf(stderr,"\n");    exit(0);}#endif

Multithreaded Quicksort

The following example tquick.cimplements the quicksort algorithm using threads.

/**  Multithreaded Demo Source* *  Copyright (C) 1995 by Sun Microsystems, Inc.*  All rights reserved.* *  This file is a product of SunSoft, Inc. and is provided for*  unrestricted use provided that this legend is included on all*  media and as a part of the software program in whole or part.*  Users may copy, modify or distribute this file at will.* *  THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING*  THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR*  PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.* *  This file is provided with no support and without any obligation on the*  part of SunSoft, Inc. to assist in its use, correction, modification or*  enhancement.* *  SUNSOFT AND SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT*  TO THE INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS*  FILE OR ANY PART THEREOF.* *  IN NO EVENT WILL SUNSOFT OR SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY*  LOST REVENUE OR PROFITS OR OTHER SPECIAL, INDIRECT AND CONSEQUENTIAL*  DAMAGES, EVEN IF THEY HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH*  DAMAGES.* *  SunSoft, Inc.*  2550 Garcia Avenue*  Mountain View, California  94043*//* * multiple-thread quick-sort.  See man page for qsort(3c) for info. * Works fine on uniprocessor machines as well. * *  Written by:  Richard Pettit (Richard.Pettit@West.Sun.COM) */#include <unistd.h>#include <stdlib.h>#include <thread.h>/* don't create more threads for less than this */#define SLICE_THRESH   4096/* how many threads per lwp */#define THR_PER_LWP       4/* cast the void to a one byte quanitity and compute the offset */#define SUB(a, n)      ((void *) (((unsigned char *) (a)) + ((n) * width)))typedef struct {  void    *sa_base;  int      sa_nel;  size_t   sa_width;  int    (*sa_compar)(const void *, const void *);} sort_args_t;/* for all instances of quicksort */static int threads_avail;#define SWAP(a, i, j, width) \{ \  int n; \  unsigned char uc; \  unsigned short us; \  unsigned long ul; \  unsigned long long ull; \ \  if (SUB(a, i) == pivot) \    pivot = SUB(a, j); \  else if (SUB(a, j) == pivot) \    pivot = SUB(a, i); \ \  /* one of the more convoluted swaps I've done */ \  switch(width) { \  case 1: \    uc = *((unsigned char *) SUB(a, i)); \    *((unsigned char *) SUB(a, i)) = *((unsigned char *) SUB(a, j)); \    *((unsigned char *) SUB(a, j)) = uc; \    break; \  case 2: \    us = *((unsigned short *) SUB(a, i)); \    *((unsigned short *) SUB(a, i)) = *((unsigned short *) SUB(a, j)); \    *((unsigned short *) SUB(a, j)) = us; \    break; \  case 4: \    ul = *((unsigned long *) SUB(a, i)); \    *((unsigned long *) SUB(a, i)) = *((unsigned long *) SUB(a, j)); \    *((unsigned long *) SUB(a, j)) = ul; \    break; \  case 8: \    ull = *((unsigned long long *) SUB(a, i)); \    *((unsigned long long *) SUB(a,i)) = *((unsigned long long *) SUB(a,j)); \    *((unsigned long long *) SUB(a, j)) = ull; \    break; \  default: \    for(n=0; n<width; n++) { \      uc = ((unsigned char *) SUB(a, i))[n]; \      ((unsigned char *) SUB(a, i))[n] = ((unsigned char *) SUB(a, j))[n]; \      ((unsigned char *) SUB(a, j))[n] = uc; \    } \    break; \  } \}static void *_quicksort(void *arg){  sort_args_t *sargs = (sort_args_t *) arg;  register void *a = sargs->sa_base;  int n = sargs->sa_nel;  int width = sargs->sa_width;  int (*compar)(const void *, const void *) = sargs->sa_compar;  register int i;  register int j;  int z;  int thread_count = 0;  void *t;  void *b[3];  void *pivot = 0;  sort_args_t sort_args[2];  thread_t tid;  /* find the pivot point */  switch(n) {  case 0:  case 1:    return 0;  case 2:    if ((*compar)(SUB(a, 0), SUB(a, 1)) > 0) {      SWAP(a, 0, 1, width);    }    return 0;  case 3:    /* three sort */    if ((*compar)(SUB(a, 0), SUB(a, 1)) > 0) {      SWAP(a, 0, 1, width);    }    /* the first two are now ordered, now order the second two */    if ((*compar)(SUB(a, 2), SUB(a, 1)) < 0) {      SWAP(a, 2, 1, width);    }    /* should the second be moved to the first? */    if ((*compar)(SUB(a, 1), SUB(a, 0)) < 0) {      SWAP(a, 1, 0, width);    }    return 0;  default:    if (n > 3) {      b[0] = SUB(a, 0);      b[1] = SUB(a, n / 2);      b[2] = SUB(a, n - 1);      /* three sort */      if ((*compar)(b[0], b[1]) > 0) {        t = b[0];        b[0] = b[1];        b[1] = t;      }      /* the first two are now ordered, now order the second two */      if ((*compar)(b[2], b[1]) < 0) {        t = b[1];        b[1] = b[2];        b[2] = t;      }      /* should the second be moved to the first? */      if ((*compar)(b[1], b[0]) < 0) {        t = b[0];        b[0] = b[1];        b[1] = t;      }      if ((*compar)(b[0], b[2]) != 0)        if ((*compar)(b[0], b[1]) < 0)          pivot = b[1];        else          pivot = b[2];    }    break;  }  if (pivot == 0)    for(i=1; i<n; i++) {      if (z = (*compar)(SUB(a, 0), SUB(a, i))) {        pivot = (z > 0) ? SUB(a, 0) : SUB(a, i);        break;      }    }  if (pivot == 0)    return;  /* sort */  i = 0;  j = n - 1;  while(i <= j) {    while((*compar)(SUB(a, i), pivot) < 0)      ++i;    while((*compar)(SUB(a, j), pivot) >= 0)      --j;    if (i < j) {      SWAP(a, i, j, width);      ++i;      --j;    }  }  /* sort the sides judiciously */  switch(i) {  case 0:  case 1:    break;  case 2:    if ((*compar)(SUB(a, 0), SUB(a, 1)) > 0) {      SWAP(a, 0, 1, width);    }    break;  case 3:    /* three sort */    if ((*compar)(SUB(a, 0), SUB(a, 1)) > 0) {      SWAP(a, 0, 1, width);    }    /* the first two are now ordered, now order the second two */    if ((*compar)(SUB(a, 2), SUB(a, 1)) < 0) {      SWAP(a, 2, 1, width);    }    /* should the second be moved to the first? */    if ((*compar)(SUB(a, 1), SUB(a, 0)) < 0) {      SWAP(a, 1, 0, width);    }    break;  default:    sort_args[0].sa_base          = a;    sort_args[0].sa_nel           = i;    sort_args[0].sa_width         = width;    sort_args[0].sa_compar        = compar;    if ((threads_avail > 0) && (i > SLICE_THRESH)) {      threads_avail--;      thr_create(0, 0, _quicksort, &sort_args[0], 0, &tid);      thread_count = 1;    } else      _quicksort(&sort_args[0]);    break;  }  j = n - i;  switch(j) {  case 1:    break;  case 2:    if ((*compar)(SUB(a, i), SUB(a, i + 1)) > 0) {      SWAP(a, i, i + 1, width);    }    break;  case 3:    /* three sort */    if ((*compar)(SUB(a, i), SUB(a, i + 1)) > 0) {      SWAP(a, i, i + 1, width);    }    /* the first two are now ordered, now order the second two */    if ((*compar)(SUB(a, i + 2), SUB(a, i + 1)) < 0) {      SWAP(a, i + 2, i + 1, width);    }    /* should the second be moved to the first? */    if ((*compar)(SUB(a, i + 1), SUB(a, i)) < 0) {      SWAP(a, i + 1, i, width);    }    break;  default:    sort_args[1].sa_base          = SUB(a, i);    sort_args[1].sa_nel           = j;    sort_args[1].sa_width         = width;    sort_args[1].sa_compar        = compar;    if ((thread_count == 0) && (threads_avail > 0) && (i > SLICE_THRESH)) {      threads_avail--;      thr_create(0, 0, _quicksort, &sort_args[1], 0, &tid);      thread_count = 1;    } else      _quicksort(&sort_args[1]);    break;  }  if (thread_count) {    thr_join(tid, 0, 0);    threads_avail++;  }  return 0;}voidquicksort(void *a, size_t n, size_t width,          int (*compar)(const void *, const void *)){  static int ncpus = -1;  sort_args_t sort_args;  if (ncpus == -1) {    ncpus = sysconf( _SC_NPROCESSORS_ONLN);    /* lwp for each cpu */    if ((ncpus > 1) && (thr_getconcurrency() < ncpus))      thr_setconcurrency(ncpus);    /* thread count not to exceed THR_PER_LWP per lwp */    threads_avail = (ncpus == 1) ? 0 : (ncpus * THR_PER_LWP);  }  sort_args.sa_base = a;  sort_args.sa_nel = n;  sort_args.sa_width = width;  sort_args.sa_compar = compar;  (void) _quicksort(&sort_args);}



Dave Marshall
1/5/1999

'기본 카테고리' 카테고리의 다른 글

[리눅스마스터 1급 2차] 과년도 문제 분석서  (0) 2011.04.11
어느 멋진 벽화????  (0) 2010.12.02
컴퓨터 자동종료 설정하기  (0) 2010.10.15
오라클 AQ (advanced queuing)  (0) 2010.10.15
SQL 로더 사용법  (0) 2010.10.12
[알아봅시다] 이통사들의 모바일 트래픽 해법

스마트폰 무제한 데이터서비스 경쟁…통화품질 장애ㆍ설비투자 부담
사용량 제한 요금제로 전환 과부하 방지

3G 이외 와이파이 등 우회망 활용
글로벌 업체들 4G망 상용화 '속도'


스마트폰 가입자 500만 돌파가 초읽기에 들어갔습니다. 지난해 11월 아이폰이 국내에 출시된지 채 1년도 안돼 기록적인 확장을 하고 있는 것입니다. 모바일 시장확산을 주문했던 정부 당국이나 이통사, 휴대폰 제조업체들까지 이같은 변화의 속도에 놀랄 정도입니다.

스마트폰 기반 모바일 사용자가 확대되면서 이동통신사의 가입자당매출액(ARPU)이 크게 확대되고 있습니다. 음성전화만을 주로 사용했던 가입자들이 무선인터넷 정액제 요금제 사용자로 전환하면서, 과거에 비해 2만∼3만원 이상의 ARPU 개선효과가 나타나고 있는 것입니다. 또한 금융, 교통, 제조, 생산 등 산업전반에 걸쳐 스마트폰을 기반으로 한 모바일 서비스가 확산되면서 다양한 비즈니스 기회도 생겨나고 있습니다.

그러나 해당 통신사 입장에서는 마냥 좋아만 할 수 없는 상황이 연출되고 있습니다. 모바일 이용자가 급증하면서 통화품질 문제, 트래픽 처리 문제가 본격적인 현안으로 부상하기 시작한 것입니다.

실제, 스마트폰 사용자라면 통화중 끊김은 물론 인터넷 접속지연 등의 장애를 경험했을 것입니다. 월 5만5000원 이상만 내면 데이터 무제한 서비스를 제공받고 있지만, 음성통화는 물론 데이터 통신에서 불편이 크다 보니 곳곳에서 소비자들의 불만이 제기되고 있습니다.

문제는 기하급수적으로 늘어나는 데이터 트래픽 때문입니다. 스마트폰을 기반으로 한 모바일 사용자가 늘어나다 보니, 3G(세대) 이동통신망 뿐만 아니라 와이파이, 유선에까지 트래픽 과부하가 걸린 것입니다. 데이터 트래픽 문제는 앞으로 스마트폰 가입자가 늘어나고 이를 기반으로 한 데이터서비스가 확산될수록, 더 심각한 양상으로 나타날 것입니다. 결과적으로 이같은 현상은 이통사에 매출과 투자에 있어 심각한 불균형을 초래하고 있습니다.

전체 매출액의 대부분을 차지하는 음성트래픽은 정체 상태에 있지만, 정작 매출에서 20∼30%를 담당하는 데이터 트래픽은 기하급수적으로 증가하면서 이통사 입장에서 보면 수익은 한정적인데 설비투자는 무한대로 늘려야 하는 부담이 생긴 것입니다.

주요 글로벌 통신기업들이 당면 현안인 트래픽 문제해소를 위해 요금제 개선, 신규 네트워크 투자, 망 중립성 등 제도개선 방안 등을 내놓고 있습니다. 글로벌 업체들의 해법은 최근 트래픽 문제가 급격히 부상하고 있는 국내 이통사들에 시사하는 바가 큽니다.

◆요금제 개선 =소셜네트워크서비스, 멀티미디어 서비스가 확대되고, 이것이 트래픽 폭증의 주요 요인으로 지적되면서 세계 주요 통신사업자들은 트래픽 부담을 줄여 나가면서 투자회수 비용을 극대화할 수 있는 요금전략을 구사하고 있습니다.

미국 AT&T의 경우, 지난해 6월 이용량에 따라 요금을 부여하는 단계별 정액제를 도입했고, 유럽의 텔리아소레나는 기존 무제한 데이터 서비스에서 데이터 한도로 사용량을 제한하는 LTE 요금제로 전환했습니다.

단기간에 모바일 시장을 확산시키기 위해서는 무제한 데이터 요금제가 최상의 조합으로 평가됩니다. 그러나 최근 무제한 데이터 요금제가 중장기적으로 네트워크 품질을 저하시키고 투자 및 수익의 불균형을 가져오는 주범으로 손꼽히고 있습니다. 특히 상위 6%가 전체 트래픽의 절반 이상을 발생하면서 형평성 문제도 유발하고 있습니다. 따라서 AT&T와 같이 초기 과감한 무제한 데이터서비스를 선보인 사업자들도 최근 상한제와 같은 신규 요금제로 속속 전환하고 있습니다.

최근 데이터 무제한 서비스를 경쟁적으로 내놓고, 무한경쟁을 벌이고 있는 SK텔레콤, KT, LG유플러스 등 국내 이통사업자들에 시사하는 바가 큰 대목입니다.

◆우회망 및 망진화 `속도' =상당수의 이통사들이 트래픽 과부하를 최소화하기 위해 3G 이외에 우회망 전략을 추진중입니다. 펨토셀이나 와이파이 등 우회망 전략은 이용자 입장에서는 서비스 품질 향상과 접속경로를 확대해주고, 사업자 입장에서는 트래픽 분산에 따른 망투자 비용의 절감을 유도합니다. KT, SK텔레콤, LG유플러스 등 국내 이통사들도 트래픽 분산과 접속경로 확대 차원에서 와이파이, 와이브로 등 우회망 전략을 전면에 내세우고 있습니다.

미국 AT&T의 경우, 올 2분기 와이파이 접속수가 전년 동기대비 5배 이상 증가한 것을 비롯해, 오는 2015년경에는 전체 트래픽에서 펨토셀, 와이파이가 차지하는 비중이 50% 수준으로 높아질 것으로 내다보고 있습니다. 일본 소프트뱅크도 올초부터 무료로 펨토셀을 지원하고 있고, 버라이존도 댁내 및 공공지역에서 대다수의 가입자에 와이파이 서비스를 제공할 예정입니다. 대용량의 트래픽을 유발하는 방송용 콘텐츠 지원을 위해서는 기존 3G, 또는 와이파이 이외에 미디어플로우 같은 방송용 네트워크를 활용하는 방안도 새로 검토되고 있습니다.

국내뿐만 아니라 해외 통신사업자들 모두 무선망인 3G 뿐만 아니라 와이파이, 펨토셀, 와이브로 등 모든 가용한 네트워크 자원을 동원, 트래픽 문제 해결에 나서고 있는 것입니다.

같은 맥락에서 소강상태를 보이던 4G 이동통신 망 고도화 사업도 속도를 내고 있습니다. 당초 이동통신사들은 3G 투자비 회수차원에서 4G 조기 상용화에 부정적인 입장이었습니다. 4G로 전환하더라도 가급적 천천히 가겠다는 게 기본 구상이었습니다. 그러나 트래픽 문제가 당면과제로 부각되면서 앞뒤를 잴 겨를이 없어진 것입니다.

3G 서비스에 착수한지 몇 년 안되는 사업자들도 와이브로(모바일 와이맥스), LTE(롱텀에볼루션) 등 4G 기술도입을 검토하고 있는 실정입니다. 국내 이통3사도 빠르면 내년부터 4G 기술인 LTE 상용화에 나서겠다는 입장입니다.

최경섭기자 kschoi@

[출처] http://www.mykit.com/kor/ele/data_22/unix_.htm

Unix

◆ 유닉스의 역사

- 1965 ; AT&T의 Bell연구소는 MIT대학, GE(General Electric)사와 함께 새로운 운영체제인 Multics를 개발할 목적으로 공동연구 착수.

- 1969 ; Bell연구소는 Multics 프로잭트를 취소.

Bell연구소프로그래머중 Tompson은 Ritchie의 도움으로 DEC사의 PDP-7이라는 시스템에서 프로그램 작업을 수행할 수 있었고,
그는 파일유틸리티(cp, mv 등)와 쉘(shell)이란 명령어 해석기를 개발.
이렇게 탄생한 시스템은 Unix란 이름을 붙였다.

- 1971 ; Ritchies는 B언어를 기초로 하여 C언어를 개발. 이때 Unix System(커널)은 PDP-11상에서 실행.
이 시스템 환경은 16Kbyte 사용자 메모리, 512byte의 디스크 장착.

이 당시 Unix 시스템이 제공하던 기능
프로그래밍 환경
단순한 사용자 인터페이스
강력한 기능을 수행하기 위해 결합가능한 유틸리티
계층적인 파일시스템
파일 포맷과 일관성 갖는 단순한 장치 인터페이스
다중사용자, 멀티프로세서 시스템
사용자에게 독립적이고 투명한 시스템구조

- 1973 ; 모든 Unix시스템을 이식성과 속도를 높이기 위하여 C언어로 재 작성.

- 1977 ; Berkely 대학에서 꾸준히 발전시켜 BSD계열의 Unix시스템을 일반에게 배포하여 500개 사이트가 개설

- 1980 ; BSD4.1(Berkely Software Development)이 발표

- 1983 ; SunOS, BSD4.2 System V가 발표

- 1984 ; 다양한 능력을 가진 수많은 플렛폼에서 100,000개의 Unix사이트가 운영

- 1988 ; AT&T와 Sun Microsystems사가 공동으로 System V Release 4 (SVR4)를 개발
이것이 후에 UnixWare와 Solaris 2로 발전된다.

- 1993 ; Novell사가 AT&T사로부터 UNIX를 구매

- 1994 ; Novell사는 X/OPEN을 "UNIX"로 명명

- 1995 ; SCO(Santa Cruz Operations)사가 Novell로부터 UnixWare를 구매
SCO사와 HP(Hewlett-Packard)사는 공동으로 64비트 Unix버전을 개발할 것을 발표

- 1996 ; IDC(International Data Corporation)에서는 1997년 3백만개의 유닉스 시스템 배포 예측

Unix 계통도

◆ 현재 사용되는 유닉스의 특징

. 여러계층으로 구성된 운영체제 (layered OS)
;하드웨어 - 커널 -(시스템콜)- 유틸리티 - Aplication

. 다중사용자(Multi-user), 다중작업시스템(Multi-task)
. Kernel(커널)시스템
;커널
프로세스(Process;현재하고 있는 작업)와 사용자들을 구분하고,
각 사용자가 CPU, 메모리, 디스크 및 I/O장치들을 포함한 하드웨어에 접근하는 것을 관리

커널의 기능은 아래과 같이 크게 몇 부분 구성되어 있다.
, 시스템의 메모리와 각 프로세스의 할당문제를 관리하는 기능
, CPU를 사용하는 순서를 정하는 일. 즉 모든 사용자가 원하는 작업을 동시에 할 수 있도록 하는 일
, 시스템에서 처리되는 각종 데이타를 변환, 전송 하는 기능
, 쉘과 연관되어 쉘에서 지시한 작업을 수행하고, 그 결과를 쉘로 보내는 일
, 파일 시스템의 접근 권한을 처리하는 일

Swap ; Process가 잠시 대기할 때 사용되는 영역(HDD공간)

데몬(Deamons) ; 계속 대기상태의 수행 ; Booting 시(Start)부터 Exit or Logout될 때까지 대기 수행.
ex : 프린터...

프로세스(Process) ; 현재하고 있는 작업. 응용프로그램 수행

OS(커널) : 소프트웨어와 사용자를 위하여 시스템(H/W)를 제어.


○ 프로세스 ; 유닉스는 기본적으로 멀티테스킹 환경이다.
프로그램을 실행하면 프로세스라는 개념으로 유닉스에서 프로그램을 관리하는데,
각각의 프로세스는 유일한 PID(Process ID)를 할당받게 된다.
ps ; 현재 시스팀에 등록된 프로세스들을 출력한다.
ps -e ; 모든 프로세스에 대한 정보를 출력한다.
ps -f ; 자세한 정보를 출력한다.
ps -u ; {ID} ID의 프로세스만 출력한다.
ex) ps -u mix1009

- 가끔 프로그램의 버그 등으로 실행에 차질이 생기고 프로그램을 정상적인 방법으로 종료하지 못하는
경우가 생기는데ps로 PID를 확인한 후 kill명령을 이용해서 프로그램을 종료할 수 있다.

Kill ; 프로세스를 종료한다.
kill -9 ; 프로세스를 강제로 종료한다. ex) kill {PID}

○ Job 제어 (foreground와 background)
; 프로그램을 terminal에서 프로그램을 실행시키면 그 terminal에선 다른 프로그램을 실행시킬 수 없다.
프로그램이 foreground로 실행되기 때문이다. 보통 terminal을 통한 사용자의 입력이 필요한
프로그램을 foreground로 실행하지만 사용자의 입력이 필요없거나,
terminal을 통한 입력이 필요없는 X Window application들은 foreground로 실행시키면 terminal은
아무 작업도 하지 않으면서 다른 프로그램도 실행시킬수 없게 된다.
실행 할때 &를 붙여주면 프로그램이 background로 실행된다.
ex) /home/mix1009> msql2d &



◆ 유닉스의 용도

1) Server
웹서버(Web server) (HTTP 서버)
메일서버 (SMTP서버)
파일전송 서버 (ftp서버)
원격접속서버 (telnet서버)
도메인 네임서버 (DNS서버)

2) 워크스테이션 ; 작업을 수행하는 시스템


◆ 유닉스 시스템의 기초

1) 계정 (Login ID) ; 8자 이내의 숫자나 소문자. 같은 ID 불허

2) 암호 ; 대소문자 구분, 6자이상
권장 ; 문자유형(알파벳, 숫자, 특수문자)을 혼합하여 사용.
대 소문자를 혼합 사용
적어도 6문자 이상 사용
사용자가 기억할 수 있는 암호사용
암호를 자주 바꾼다.
"passwd" 명령을 이용하여 변경가능

3) 원격접속 ; telnet ;윈도우스에서 텔넷을 접근하려면 텔넷 창에서 " telnet 시스템주소"를 입력

4) 접속해제 ; logout ; 시스템을 종료
exit ; 쉘을 종료


◆ 유닉스의 쉘(Shell)기능 ; 사용자 프로그램과 커널과의 연결하는 역할.

Kernel - Shell - 사용자 프로그램

1) 본 쉘 (Bourne shell)
2) 콘 쉘 (Korn shell)
3) C 쉘 (C shell)

시스템이 처음 로그온 하면 미리 정해진 기본쉘이 동작 (login shell)

변경시 "csh"라고 치면(C shell로 변경)되고, 원래대로(bach) 갈 때에는 "exit"한다.

쉘이 제공하는 기능
. 명령라인 . 내장명령어 . 환경변수 . 재 지정(Redirection) . 파이프 (pipe)
. 자식(sub)쉘 . 백그라운드 작업 . 명령어 치환 . 히스토리 .스크립트


◆ 유닉스 파일시스템 구조

Unix 파일시스템 구조


◆ UNIX ADMIN ; UNIX는 멀티유저 시스팀이기 때문에, 각각의 사용자가 사용하는 디렉토리가 따로 있으며,
시스템 실행에 중요한 요소인 실행 화일이나 라이브러리 파일은
시스템 관리자만이 지우거나 갱신이 가능하도록 되어있다.

사용자는 자기의 디렉토리(Home Directory) 밑의 화일에 한해서만 자유로이 접근이 가능하다.
Home Directory는 /home/{사용자ID}로 되며 로그인해서 쉘을 실행하면 여기서 시작하게 된다.

wow linux설치시 HDD용량 배분
swap ; 256 ; RAM의 2배 정도
/ ; 60 MB 정도
/usr ; 1600 MB 정도
/tmp ; 100 MB 정도
/var ; 500 MB ; home과 비례
/home ; 나머지

</usr>

/usr는 실제 작업을 위한 응용 패키지들이 설치되어 있는 디렉토리이다. 따라서 많은 서브디렉토리를 포함하고 있다.

</usr/bin>

/usr/bin은 대부분의 실행 화일이 위치하는 디렉토리다. 유닉스에서 제공하는 기본 툴들이 대부분 여기 들어있다.

</usr/lib>

/usr/lib는 공유 라이브러리와 정적 라이브러리를 포함하고 있다. 이 화일들은 일반적으로 사용되는 많은 프로그램에서 호출되는 코드들을 포함하고 있다. 어떤 프로그램이 공유 될 수 있는 루틴을 단독으로 포함하지 않고, 그 루틴을 일반 장소인 /usr/lib 안에 저장한다. 이렇게 함으로서 실행 화일의 크기를 작게 만들어 사용자의 공간을 넓힐 수 있다.

</usr/include>

/usr/include는 C 컴파일러를 위한 include 화일들을 포함하고 있다. 이 화일은 데이터 구조 이름과 서브루틴, 상수 같은 C로 작성된 프로그램에서 사용되는 내용을 담고 있다. printf() 함수가 선언되어 있는 stdio.h 같은 헤더 화일을 찾을 수 있다.

</dev>

/dev 안의 화일들은 디바이스 드라이버들이다. 이것들은 디스크 드라이브, 메모리, CDROM, audio 등과 같은 시스팀 디바이스나 자원들을 액세스하는데 사용된다. (유닉스에서는 모든 디바이스들을 화일과 같이 취급한다.)

</etc>

/etc는 시스템 설정 화일, 프로그램, 유틸리티 등 다양한 프로그램들을 포함하고 있으며 대부분의 화일들은 관리자에 의해 사용되는 것이다.

</tmp>

많은 프로그램들은 여러 정보가 임시 화일 안에 저장되는 것을 필요로 한다. 이런 화일들이 위치할 장소가 /tmp 이다.

</usr/local>

/usr/local은 /usr에 포함된 것과 매우 유사하고, 시스템에 반드시 필요로 하는 것은 아니지만, 매우 유용한 것들을 포함하고 있다. 일반적으로, 시스팀 관리자가 추가의 프로그램을 인스톨할 때 /usr/local 밑에 인스톨하게 된다.
예: /usr/local/httpd : NCSA Web Server가 설치되어 있는 디렉토리
/usr/local/bin : 추가 설치된 프로그램의 실행화일이 있는 디렉토리

</usr/man>

이 디렉토리는 Manual page를 포함하고 있다. Manual Page는 man이나 xman을 사용해서 볼수 있다.



◆ 유닉스의 파일명

- 대문자(A~Z), 소문자(a~z), 숫자(0~9), 밑줄(_), 마침표(.), 쉼표(,)
- 14문자 까지만 비교하므로 14문자 이내에서 작성.


◆ 유닉스의 파일유형

- 일반파일
d 디렉토리
l 심볼릭 링크
b 블록 특수파일
c 문자 특수파일
p "pipe"특수파일


○ . 과 .. ; .은 자신의 디렉토리, ..은 부모디렉토리 항목

○ 절대경로명 ; /(루트)부터시작하여 해당파일 까지 모든 경로표시.

○ 상대경로명 ; 현재 작업디렉토리 중심으로 부모디렉토리는 ../../directory 등으로 표시

○ 링크만들기

- 하드링크(hard link); 파일 실제 내용인 inode에 대한 정보를 공유.
ex. lntest.txt testlink.txt ; test.txt 파일을 testlink.txt 로 하드링크.

◇ inode ; ls -il ; i 옵션을 주면 파일 왼쪽에 inode번호가 표시된다.

- 심볼릭링크(soft link) ; 실제로 링크가 되는 것이 아니고 링크된 파일 정보만 가진다.
ex.ln -stest2.txt testlink2.txt ; test2.txt 파일을 testlink2.txt 로 심볼릭링크.



◆ 파일 접근권한 (permission) ; 유닉스의 화일 사용 허가 ;
유닉스 시스템은 다중 사용자 시스템이기 때문에 다른 사용자들로부터 각자의 화일들을 보호하기 위하여,
화일
사용 허가라 개념을 도입한다. 모든 화일은 특별한 사용자나 그룹에게 소유되어 있다.
ls -al 의 명령을 주면 파일이나 디렉토리의 접근 상태를 보여준다.

파일유형

user, owner
(소유자)

group

other

-

r

w

x

r

w

x

r

w

x

일반화일

4

2

1

4

2

1

4

2

1

r ; read(읽기), w ; write(쓰기), x ; execute(실행)

user는 화일을 만든 유저,
group은 화일을 만든 유저와 같은 그룹에 있는 유저,
others는 그 밖의 모든 유저를 말한다.

◇ chmod (change file modes)

- 기호를 이용 접근권한 변경 방법

기호

접근권한 의미

+

부여

chmodo+rw test.txt ; 파일 test.txt을 사용자에게 읽기와 쓰기 권한부여

-

제거

chmodg-rw test.txt ; 파일 test.txt을 그룹에게 읽기와 쓰기 권한제거

=

설정

chmodu=rw test.txt ; 파일 test.txt을 유저에게 읽기와 쓰기 권한설정

chmod u+rw file명 : user에게 read, write 권한을 준다.
(user에게 write권한이 없으면 화일을 지울수도 없다.)
chmod a+r file명 : user, group, other에 read 권한을 준다.
chmod go-wx file명 : group, other에게서 write, execute 권한을 뺐는다.

- 숫자를 이용 접근권한 변경 방법

user

group

other

-

r

w

x

r

w

x

r

w

x

4

2

1

4

2

1

4

2

1

7

6

6

chmod 766 ; user에게는 읽기와 쓰기 실행 권한을 부여
group에게는 읽기와 쓰기 권한을 부여
other에게는 읽기와 쓰기 권한을 부여

◇ umask ; 사용자가 파일을 생성 할 때 부여되는기본 접근 권한; 8진수의 보수값으로 설정
ex. umask 011 ; 파일 생성시 permission 766값으로 설정된다.


◆ ftp ; ftp 사이트에 접속 했을 때 다음과같은 명령사용

명령어

기능

dir

디렉토리 보기

cd

디렉토리 바꾸기

lcd

로컬(client)컴퓨터(내컴퓨터)의 디렉토리 변경

hash

다운로드 상태 표시

get

파일 다운로드 받기

mget

여러개의 파일 다운로드 받기

put

파일 올리기

mput

여러개의 파일 올리기

ascii

아스키모드로 전송하기

binary

바이너리 모드로 전송하기

!

ftp접속중 내 컴퓨터 명령 실행시 명령어 앞에 붙인다

prompt

대화식 모드

bye

종료

◆ Ws_Ftp ;http://www.ipswitch.com; 대체로 많이 사용하는 FTP

◆ ALFTP ;
http://www.altools.co.kr; 국내에서 만든 FTP

◆ Anonymous FTP ; 누구나 파일일 다운하고 파일을 올릴 수 있는 서비스.
ex. 서울대학교
ftp.snu.ac.kr
데이콤
ftp.dacom.co.kr

◆ 새롬데이터맨 ;http://www.serome.co.kr; telnet접속을 위해 많이 사용되는 애물레이터.

◆ X-manager ; 네트워크로 연결된 UNIX시스템의 응용프로그램을 Windows에서 실행시키는 소프트웨어.
http://www.netsarang.co.kr

◆ ptk laek gul
cks@disys.korea.ac.kr




- UNIX 기본 명령어

Linux/Unix 명령어

설 명

MS-DOS 비교

./x

x 프로그램 실행
(현재 디렉토리에 있는 것)

x

/

이전에(↑) / 다음에(↓) 입력했던 명령어

doskey

cdx(또는cd /x)

디렉토리 X로 가기

cd

cd .. (또는cd ../ 또는 cd /..)

한 디렉토리 위로 가기

cd..

x다음[tab] [tab]

x 로 시작하는 모든 명령어 보기

-

adduser

시스템에 사용자 추가

/

ls (또는dir)

디렉토리 내부 보여주기

dir

cat

터미널 상의 텍스트 파일 보기

type

mvx y

파일 x를 파일 y로 바꾸거나 옮기기

move

cpx y

파일 x를 파일 y로 복사하기

copy

rm x

파일 지우기

del

mkdirx

디렉토리 만들기

md

rmdirx

디렉토리 지우기

rd

rm -rx

디렉토리 x를 지우고 하위도 다 지우기

deltree

rm p

패키지 지우기

-

df (또는dfx)

장치 x의 남은 공간 보여주기

chkdsk ?

top

메모리 상태 보여주기(q는 종료)

mem

manx

명령어 x에 관한 매뉴얼 페이지 얻기

/

lessx

텍스트 파일 x 보기
(리눅스에서는 더 많은 필터 적용 가능)

type x | more

echo

어떤 것을 echo 화면에 인쇄한다.

echo

mc

UNIX를 위한 노턴 커맨더

nc

mount

장치 연결(예: CD-ROM, 연결을 해제하려면 umount)

-

halt

시스템 종료

-

reboot ([ctrl] + [alt] +[del])

시스템 다시 시작하기

[ctrl] + [del] + [del]

고급 명령어

chmod <권한> <파일>

파일 권한(permissions) 변경

ls -lx

파일 x의 자세한 상황을 보여줌

ln -sx y

x에서 y로 심볼릭 링크를 만들어 줌

find x -name y -print

디렉토리 x안에서파일 y를 찾아서 화면에 그 결과를 보여줌

ps

지금 작동중인 모든 프로세스들을 보여줌

killx

프로세스 x를 종료 (x는 ps 명령으로 알 게 된 PID)

[alt] + F1 - F7

터미널 1-7까지 바꾸기 (텍스트 터미널에서; F7은 X-윈도우(시작될때))

lilo

부트 디스크를 만듦

용어

symlink

다른 파일이나 디렉토리로 심볼릭 링크. 윈도유98의 바로가기 같은 것

shell script

여러 명령어들을 차례로 수행하게 한 것. MS-DOS의 배치 파일 같은 것

♣ ls ; 도스의 dir 과 같이 현재 디렉토리 안의 모든 파일과 디렉토리명을 표시.
자세한 정보를 보려면 ls -l 을 사용 합니다 ex) ls -l test.*

ls -al >test.txt ; 현재 디랙토리 리스트를 test.txt라는 파일로 출력
ls -al > lpr ; 프린터로 바로 출력
ls >> test.txt ; 이전test.txt의 내용에 ls내용을 추가하여 기록.
ls | sort ;
ls -l ; 화일 허용 여부, 소유자, 그룹, 크기, 날짜 등을 출력한다.
ls -F ; 화일의 형태와 함께 출력한다. (/ : 디렉토리, * : 실행화일, @ : 심볼릭 링크 )
ls -R ; 서브 디렉토리의 내용을 포함하여 출력한다.

♣ ls -F ; 이 명령을 주었을 때 파일명 뒤에 붙는 문자로 파일유형을 알 수 있다.
"/"는 디렉토리, "*"는 실행가능한 파일, "@"는 심볼릭링크

♣ mkdir ; MaKe DIRectory ; 디렉토리 생성 ex. mkdir home1 ; home1디렉토리 생성

♣ pwd ; print working directory ; 현재 작업 디렉토리를 알려준다.

♣ reboot ;

♣ cd ;도스의 cd 명령과 같이 디렉토리를 이동할때 사용 합니다. 이때 도스명령과는 달리
cd 와 .. 사이에 스페이스를 넣어야 합니다ex) cd ..

♣ cd ; logon directory로 간다.

♣ cd / ;root(/)로 간다.

♣ pwd ; 현재 디렉토리를 확인 할때 사용 합니다.

♣ cp ; 화일(들)을 다른 화일 이름으로 복사하거나 다른 디렉토리로 복사한다.
복사 하려는 파일이 디렉토리일 경우 하위 디렉토리까지 모두 복사 합니다.
ex) cp -r test1 test2
cp -i ; 같은 화일명을 갖는 화일이 있을 경우, 사용자 확인후 복사한다.
cp -r ; 서브 디렉토리를 포함한 모든 화일 복사한다.

♣ mv ; 화일(들)을 다른 화일이나 디렉토리로 이동.
ex) mv test/data test1/data ;test/data 파일을 test1/data 로 이동 합니다.
mv -f ; 옮겨질 디렉토리에 존재하는 화일이 있으면 덮어쓴다. (force)
mv -i ; 옮겨질 디렉토리에 존재하는 화일이 있으면 확인한다. (interactive)

♣ rm ; 특정 화일(들)을 지우는 명령 . ex) rm test
유닉스 하에서 화일을 지우면, 복구가 불가능하다.
rm -i ; 지우기 전에 확인한다. (interactice)
rm -r ; 서브 디렉토리를 포함하여 지운다. (recursive)

♣ mkdir / rmdir ; 새로운 디렉토리를 만들거나 삭제할때 사용 합니다. ex) mkdir test, rmdir test

♣ rmdir ; 비어 있는 디렉토리를 지운다.
rmdir을 사용할 때는 현재 디렉토리가 지워질 디렉토리 안에 포함되어 있으면 안된다.
(화일을 포함하고 있는 디렉토리를 지우려면 rm -r을 사용한다.
이 명령은 많이 사용하지만 사용할때 조심해야하는 명령이다.
사용자의 디렉토리 전체를 지워버릴수도 있다.)

♣ chmod ; 파일을 읽고 쓸수있는 권한을 변경할때 사용합니다.
ex) chmod 666 test
0 : 모든 허가 안함
4 : 읽기 허가
5 : 읽기/실행 허가
6 : 읽기/쓰기 허가
7 : 읽기/쓰기/실행 허가

♣ cat ;현재 파일의 모든 내용을 출력 합니다 도스의 type 문과 같습니다.
cat > or cat >> 는 DOS에서의 copy con 과 같다.


♣ du ; 현재 디렉토리와 포함된 서브 디렉토리의 사용 용량을 출력한다.
ex) du -k : KByte 단위로 표시

♣ df ; 하드의 전체 용량 및 남은 용량을 출력한다.
ex) df -k : KByte 단위로 표시

♣ adduser ; root에서 user추가로 만들 때 사용 ex. adduser study ;study ID작성

♣ su ; ex. su study ; study root로 들어감

♣ passwd ; password 작성

♣ ls -al ; 숨김 화일까지 보여준다.

♣ ls -F ; 이 명령을 주었을 때 뒤에 붙어있는 문자가 "/"는 디렉토리, "*"는 실행가능한 파일, "@"심볼릭 링크의 뜻.

♣ !! ; 바로 앞 실행을 다시 실행.

♣ 명령어 뒤에 &사용 (백그라운드 작업) ; 시스템 여유시간에 수행지시.

♣ 파이프명령어(|) ; ex. ls | sort ; 리스트를 소트

♣ alias ; 명령어 치환기능
alias kk ls -al ; "ls -al"을 kk로 바꾸어 수행하는 경우

♣ history ; 이전에 사용한 명령을 보여준다.
! history번호를 치면 수행

♣ echo $SHELL ; 사용 shell보기

♣ chsh ; shell바꾸기

♣ setenv ;

♣ shutdown

♣ shutdown -r now

♣ cron ; 분 시 일 월 요일 ex. 30 4 1 * * ; 매월 1일 4시 30분에 cron 명령실행

♣ floppy disk사용하기
mnt/floppy 에 설치하는 경우 (root에서)
mount /dev/fd0 /mnt/floppy
ls /mnt/floppy ; 확인
cd /mnt/floppy
ls -al ; floppy disk 내용이 보인다


♣ more ; 주어진 화일의 내용을 한 화면씩 출력시킨다.

♣ man ; 주어진 명령이나 자원들의 매뉴얼을 출력한다.

♣ grep ; 주어진 패턴(찾을문자)을 포함하는 화일의 라인을 출력시킨다.
( -i ; 대 소문자 무시, -n ; 라인 앞부분에 행번호 붙인다)
ex) grep main *.c ; *.c 화일 내용중에 main을 포함하는 문자열을 찾아서 화일명과 라인, 그 내용을 출력한다.


♣ find ; 화일을 찾아주는 유틸리티.
ex) find . -name "*.tex" -print ; 현재 디렉토리(.)에서 그 이하의 모든 디렉토리에서 확장자가 tex인
확장자를 가진 모든 화일을 찾아서 화면에 출력해준다.


♣ Redirection ; [ > {file명} , >> {file명} ]
이를 이용함으로써 명령의 결과를 화일로 얻을 수가 있다.
ex) /home/mix1009> ls > file-list ; ls의 결과를 file-list 화일에 저장한다.
/home/mix1009> ls -l >> file-list ; ls -l의 결과를 file-list에 추가(append)한다.

♣ 파이프(Pipe) ; [ | {명령어} ]
파이프라는 것은 여러 명령을 혼합하여 사용할 때, 한 명령의 결과가 다른 명령으로 전송되는 통로라고 이해할 수 있다.
ex) /home/mix1009> ls | sort
/home/mix1009> ls -l /usr/bin | more
/home/mix1009> ls -al | grep rc | sort


♣ nslookup ;

♣ arp ;

♣ ping ;

♣ rlogin ;

♣ telnet ;

♣ netstat ;

♣ traceroute ;

♣ iconfig ;

♣ FTP(File Transfer Protocol) ;

♣ whois ;

*****************************************************************************************************************************

리눅스에서 자주 쓰이는 명령어들입니다.. 간단한 설명해 둔것입니다..

alias(명령어 간소화하기)
apropos(관련된 명령어 찾기)
arch(컴퓨터 종류 알기)
arp(같은 서브넷의 IP 보여주기)
at(작업 시간 정하기)
atd(계획성 있는 작업 실행하기)
awk(특정 패턴 문자 처리하기)
a2p(펄 파일로 바꾸기)
badblocks(배드 블럭 검사하기)
bc(계산기)
biff(메일 수신 소리로 확인하기)
bg(후면작업; 배경화면 설정)
bind(키나 함수 순서 결합하기)
break(루프 빠져나가기)
cal(달력보기)
builtin(내부 명령어 알아보기)
case(조건 처리하기)
cat(화면상에서 파일 보기)
cd(디렉토리 변경하기)
cfdisk(디스크 설정하기)
chattr(파일 속성 변경하기)
chfn(사용자 정보 변경하기)
chgrp(파일, 디렉토리가 속했던 그룹 바꾸기)
chmod(파일 권한 바꾸기)
chown(파일 주인 바꾸기)
chsh(지정된 셸 바꾸기)
cksum(CRC값을 점검한다)
clear(화면 청소하기)
clock(CMOS 시각을 조정하기)
cmp(파일 비교하기)
colcrt(문자 변환 필터)
colrm(열 삭제하기)
column(가로 정렬하기)
comm(파일 비교 출력하기)
command(명령어 알아보기)
continue(루프 계속돌기)
cp(파일 복사하기)
cpio(복사본 만들기)
crontab(cron을 관리한다)
csplit(파일에 서식, 규칙 정하기)
cut(필요한 필드만 출력하기)
date(날짜 보기)
dd(블럭장치 읽고 쓰기)
debugfs(ext2 파일 시스템 디버깅하기)
declare(변수 선언하기)
df(파일 시스템의 사용량 보기)
dirs(디렉토리 목록 표시하기)
dmesg(부팅 메시지 보기)
dnsdomainname(DNS 이름 출력)
domainname(NIS 이름 출력&설정)
du(디렉토리와 파일의 용량 파악하기)
dumpe2fs(파일 시스템 정보 보기)
echo(표준 출력하기)
eject(장치 해제하기)
elm(메일 관련)
enable(내부 명령어 지정)
env(환경변수 출력하기)
eval(인수 읽기)
exec(셸 명령어 실행하기)
exit(종료하기)
expand(탭을 공백으로 변환하기)
export(변수 지정하기)
e2fsck(파일 시스템 복구하기)
fc(지정된 편집기 받기)
fdformat(플로피 디스크 포맷하기)
fdisk(파티션 나누기)
fg(지정된 작업을 전면 프로세스로 시작하기)
file(파일 종류 보기)
find(파일 찾기)
finger(사용자 정보 알기)
fold(정형화하기)
fmt(정형화하기)
for(반복 실행하기)
free(메모리 사용량 알아보기)
fsck(파일 시스템 검사하기)
fstab(파일 시스템에 대한 고정적인 정보 저장하기)
ftp(파일 전송 프로그램)
fuser(프로세스 ID 출력)
getkeycodes(매핑 테이블 출력하기)
grep(특정 문자(열) 검색하기)
gzexe(실행 파일 압축하기)
gzip(압축하기)
halt(시스템 종료하기)
hash(기억해 두기; index 역할)
head(파일의 앞부분 출력하기)
help(도움말 보여주기)
host(호스트 정보 보기)
history(사용 명령어 목록보기)
hostname(서버 이름 알기)
id(계정 정보 알기)
if(조건문 실행하기)
ifconfig(랜카드에 주소 할당하기)
imolamod(모듈 설치하기)
inetd(인터넷 서비스의 최상위 데몬)
init(실행 단계 정하기)
ispell(철자법 검사하기)
jobs(수행중인 프로세스 알기)
kbd_mode(키보드 모드 출력하기)
kill(프로세스 죽이기)
klogd(커널 로그 데몬)
ldd(공유 라이브러리의 의존성 알기)
less(페이지 단위로 출력하기)
let(정규식 표현하기)
lilo(부팅하기)
ln(링크하기)
locate(패턴에 맞는 파일 찾기)
login(로그인하기)
logger(시스템 로그 기록하기)
logname(사용자 로그인명 보여주기)
logout(로그인 셸 종료하기)
look(특정 단어 검색하기)
losetup(중복 장치 확인하기)
lpd(프린트 데몬)
lpq(현재 프린트 작업 상태 출력하기)
lpr(출력하기)
lprm(대기열에 있는 문서 삭제하기)
ls(디렉토리 내용보기)
lsattr(파일 시스템의 속성 보여주기)
lsdev(하드웨어 장치 출력하기)
lsmod(모듈 정보 출력하기)
mail(메일 관련)
make(컴파일하기)
man(매뉴얼 보기)
mattrib
mbadblocks
mcd
mcopy
mdel
mdeltree
mdir
mesg(메시지를 받을 수 있는지 확인하기)
mformat
minfo
mkdir (디렉토리 만들기)
mke2fs(파일 시스템 생성하기)
mkfs(파일 시스템 만들기)
mknod(특수 파일 만들기)
mkswap(스왑 영역 지정하기)
mlabel
mmd
mmount
mmove
mpartition
mount(장치 연결하기)
more(화면 단위로 출력하기)
mrd
mren
mtoolstest
mtype
mutt(메일 관련)
mv(파일 옮기기)
mzip
netstat(현재 네트웍 상황 보기)
nice(프로세스 우선 순위 변경하기)
od(8진수로 파일 보기)
passwd(암호 입력하기)
pidof(실행중인 프로그램의 프로세스 ID 찾기)
pine(메일 관련)
ping(네트웍 확인하기)
popd(pushd 취소)
ps(프로세스 상태 알기)
pstree(프로세스 상관관계 알기)
pwd(절대경로 보여주기)
quota(디스크 한계량 알기)
rarp(rarp 테이블 관리하기)
rcp(원격 호스트에 파일 복사하기)
rdev(루트, 스왑장치, 램 크기, 비디오 모드를 조사하고 설정하기)
rdate(네트웍으로 시간 설정하기)
reboot(재부팅하기)
rmmod(모듈 지우기)
readonly(읽기 전용으로 표시하기)
renice(프로세스 우선 순위 바꾸기)
reset(터미널 초기화하기)
restore(다시 저장하기)
rlogin(바로 접속하기)
rm(파일 지우기)
rmdir (디렉토리 지우기)
route(라우팅 테이블 추가/삭제하기)
rpm(프로그램 추가/삭제)
rpm2cpio(rpm을 cpio로 변환하기)
rsh(원격으로 명령어 실행하기)
rup(호스트 상태 출력하기)
rusers(호스트에 로그인한 사용자 출력하기)
rwall(호스트 사용자에게 메시지 뿌리기)
script(기록하기)
set(변수값 설정하기)
setup(시스템 관련 설정하기)
showmount(호스트의 마운트 정보 보여주기)
shutdown(전원 끄기)
sleep(잠시 쉬기)
source(스크립트 번역하기)
split(파일 나누기)
ssh(암호화된 원격 로그인하기)
stty(터미널라인 설정 보여주기)
su(계정 바꾸기)
suspend(셸 중단하기)
swapoff (스왑 해제하기)
swapon(스왑 활성화하기)
sync(버퍼 재설정하기)
syslogd(로그인 과정 설정하기)
tac(거꾸로 보기)
tail(문서 끝부분 출력하기)
talk(이야기하기)
tar(파일 묶기)
tcpdchk(tcp wrapper 설정하기)
tcpmatch(네트웍 요청에 대해 예측하기)
tee(표준 입력으로부터 표준 출력 만들기)
telnet(원격접속하기)
test(테스트하기)
times(셸에서의 사용자와 시스템 시간 출력하기)
top(cpu 프로세스 상황 보여주기)
tr(문자열 바꿔주기)
true(종료 코드 리턴하기)
type(유형 보기)
ul(밑줄 처리해서 보여주기)
ulimit(제한하기)
umask(매스크 모드 설정하기)
umount(장치 해제하기)
unalias(별명 제거하기)
uname(시스템 정보 보기)
unexpand(공백 문자를 탭으로 변환하기)
uniq(중복된 문장 찾기)
useradd(사용자 계정 만들기)
userdel(계정 삭제하기)
usermod(사용자 계정정보 수정하기)
unset(설정 변수 해제)
uptime(시스템 부하 평균 보여주기)
users(로그인된 사용자 보여주기)
w(시스템에 접속한 사용자 상황 알아보기)
wait(프로세스 기다리기)
wall(모든 사용자에게 메시지 보내기)
wc(문자, 단어, 라인수 세기)
whatis(명령어의 간단한 설명보기)
while(루프 명령어)
who(사용자 알기)
write(콘솔 상에서 간단한 메시지 보내기)
xcopy(반복적으로 복사하기)
XFree86
ypchfn(NIS에서 사용하는 chfn 명령어)
ypchsh(NIS에서 사용하는 chsh 명령어)
yppasswd(NIS에서 사용하는 passwd 명령어)
zcat(압축 파일 보기)
zcmp(압축 파일 비교하기)
zforce(강제로 gz 만들기)
zgrep(압축 상태에서 grep 실행하기)
zmore(압축 상태에서 more 실행하기)
znew(.Z 파일을 .gz로 다시 압축하기)

*****************************************************************************************************************************


압축관련


♣ tar ; 여러 파일들을 하나로 묶는 역할을 하는 명령.
( -c ; 묶음 파일 생성, -x ; 하나의 파일명로 묶어진 파일을 푼다. -f ;파일명 보존)
ex) tar cf {디렉토리 or 파일} {file name.tar} ; 하나의 파일로 묶을 때
tar xf {file name.tar} ; 하나 파일로 풀때
tar vf {file name.tar} ; 하나의 파일로된 내용 보여줌
tar tf {file name.tar} ; 목록 보기

ex : tar cfv filename.tar 디렉토리 or 파일
tar cfv 0510xxx.tar www : www디렉토리 모두를 0510xxx.tar로 하나의 파일로 묶을 때


♣ gzip (GNU zip)

♣ compress / uncompress




인증관련

.htaccess 을 아래 내용으로 text파일로 작성하여 해당 디렉토리에 이스키모드로 FTP를 이용하여 올림
(또는 vi 편집기로 작성)

AuthName Name < == 그냥 이름

AuthType Basic

AuthUserFile /home/user_id/www/folder/.htpasswd <== pwd명령어로 해당 경로 입력

AuthGroupFile /dev/null

<Limit GET POST>

require valid-user

</Limit>


telnet 접속하여 아래와 같이 입력 하면
.htpasswd가 생성됨

htpasswd -c .htpasswd 원하는아이디
New password: <== 패스워드 입력
Re-type new password: <== 패스워드 재입력



커널(kernel) : 하드웨어와 소프트워어 연결 中 ; Windows 경우 부팅시 구름 그림 화면 나오는 시간에 행해짐

kernel / 커널

운영체제에서 가장 기초적이고 핵심적인 기능을 수행하는 부분으로 운영체제의 다른 부분들에 대한 기본 서비스를 제공하며 주기억 장치에 상주하게 된다.

커널은 주로UNIX 운영체제에서 사용되는 용어이며, 같은 의미로 nucleus와 core도 많이 사용된다. 커널은 shell과 대조되는데, shell은 운영체제의 가장 외곽 부분으로 사용자들의 커맨드와 대화를 수행한다.

커널은 그시스템의 모든 자원(하드웨어 및 소프트웨어)을 관리하고, 준비해서 사용자들의 작업이 수행될 수 있게 한다. 커널의 기능은 아래과 같이 크게 몇 부분 구성되어 있다.

  • 시스템의 메모리와 각 프로세스의 할당문제를 관리하는 기능
  • CPU를 사용하는 순서를 정하는 일. 즉 모든 사용자가 원하는 작업을 동시에 할 수 있도록 하는 일
  • 시스템에서 처리되는 각종 데이타를 변환, 전송 하는 기능
  • 쉘과 연관되어 쉘에서 지시한 작업을 수행하고, 그 결과를 쉘로 보내는 일
  • 파일 시스템의 접근 권한을 처리하는 일

comphy on IMVU


comphy of IMVU.com


S/W 제어
윈도우 : 시작 -> 실행 -> 열기.
열기 부분에 보면 키보드 입력이 가능하다. 이 곳에 shutdown -s -t 3600 을 입력하면 PC는 1시간 후에 컴퓨터가 자동 종료한다. 3600은 초를 나타내는 시간이다. 7200을 치면 2시간 동안 PC를 사용할 수 있다.

'기본 카테고리' 카테고리의 다른 글

어느 멋진 벽화????  (0) 2010.12.02
유닉스 쓰레드 프로그래밍  (0) 2010.11.15
오라클 AQ (advanced queuing)  (0) 2010.10.15
SQL 로더 사용법  (0) 2010.10.12
소스인사이트 단축키(2)  (0) 2010.10.11

A Short Tutorial on How to Use mpc.pl and mwc.pl

This tutorial shows how to create a small workspace with 3 projects. The first project is a "hello world" program. The second project is a shared library which prints "hello from hello_dll_project.cpp". The third project is in another directory, and it prints "Hello Sailor" and then calls the function in the shared library. I compile these projects with make, nmake and with visual studio 8.0.

Installation

If you need to install for linux go here before you try to run mpc.

Basic Terms

Go here for some basic notes on mpc, mwc and syntax.

Download Example

You can download the sample files in zip format or tar.gz format.

This is the directory structure and its basic contents:

foo/ # the main directory
foo/hello_project # contains hello and hello_dll projects
foo/hello_sailor_project # contains hello_sailor project
foo/include # contains include file
foo/bin # contains nothing untill projects are built

./sample_workspace.mwc

This is a sample workspace. It consist of 3 different projects in 2 directories.

./hello_project/hello_project.mpc

This is a project that illustrates the basics of naming an executable, installing it, specifying the include paths, specifying the source files and specifying the header files.

./hello_project/hello_dll_project.mpc

This is a shared library or dll project. It illustrates how to install in differnt directories for different OS's with the specific command. Illustrates how to pass compiler flags for Microsoft declspec(dllimport) and declspec(dllexport) specifications. The HELLODLL macro interacts with hello.h to generate these statements. It illustrates how to include a dllmain function, for Microsoft targets.
For the linux target OS, the ouput is put into /usr/local/cvs-user/lib which is available for all users to access. This directory is included in /etc/ld.so.conf. See here for instructions on how to set this up in gentoo.

./hello_sailor_project/hello_sailor_project.mpc

This illustrates the after command which makes this project dependent upon hello_dll. It also illustratetes linking which is conditional upon the operating system.

./hello_project/hello.cpp

This is the classic hello world program, except that it includes a file hello.h.

./include/hello.h

This is a header file full of macros, for specifying functions, and their linkage flags, STDCALL, dllexport etc. For linux all the Microsoft giberish disappears.

./hello_project/hello_dll.cpp

This file has one function, which says "hello from hello_dll.cpp". It has the Microsoft name manglers in its declaration.

./hello_project/dll.main.cpp

This file contains the Microsoft specific, dllmain function.

./hello_sailor_project/hello_sailor.cpp

This program illustrates calling a function in a shared library.

Command line syntax

cd foo
#to create for make:
mwc.pl sample_workspace.mwc
#to create for nmake
mwc.pl sample_workspace.mwc -type nmake
#to create for vc8
mwc.pl sample_workspace.mwc -type vc8

Configuration Options

When building for Microsoft platforms there are several different options for compiling and linking. These options can be found by opening one of the makefiles for a specific project, for example Makefile.hello.mak. The options are listed toward the beginning of the file. For example, Makefiles generated for nmake have the following options:

  • "Win32 Debug"
  • "Win32 Release"
  • "Win32 Static Debug"
  • "Win32 Static Release"

'Computer Science' 카테고리의 다른 글

[알아봅시다] 이통사들의 모바일 트래픽 해법  (0) 2010.10.31
Unix 개괄  (1) 2010.10.21
Perl 프로그래밍 개요  (0) 2010.10.15
소스인사이트 단축키  (0) 2010.10.08
유닉스(UNIX)개발관련 지침서  (0) 2010.09.18

+ Recent posts