Skip to content
This repository has been archived by the owner on Jun 28, 2019. It is now read-only.

Commit

Permalink
exercise: 8.26
Browse files Browse the repository at this point in the history
  • Loading branch information
mofaph committed Jul 20, 2013
1 parent b71353d commit 11959bf
Show file tree
Hide file tree
Showing 6 changed files with 719 additions and 0 deletions.
42 changes: 42 additions & 0 deletions exercise/ex8-26/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Makefile for ex8-26

# [email protected]
# 2013-7-7

CC = gcc
CFLAGS = -Wall

PROGRAM += t
PROGRAM += t-job

OBJS += ex8-26.o
OBJS += random_fork.o
OBJS += job.o

TOBJS += t-job.o

PHONY += all
PHONY += clean
PHONY += TAGS

.PHONY: $(PHONY)

all: $(PROGRAM)

t: $(OBJS)
$(CC) $(CFLAGS) $^ -o $@

t-job: t-job.o job.o
$(CC) $(CFLAGS) $^ -o $@

ex8-26.o: shellex.c
$(CC) $(CFLAGS) -c $< -o $@

t-job.o: t-job.c job.h
job.o: job.c job.h

TAGS:
find . -type f -name "*.[ch]" -print | xargs etags -

clean:
rm -f $(PROGRAM) $(OBJS) $(TOBJS)
216 changes: 216 additions & 0 deletions exercise/ex8-26/job.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/*
* 8.26
*
* [email protected]
* 2013-7-14
*
* 这个文件包含了用来处理作业控制的代码
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "job.h"

/*
* 作业控制列表从 1 开始计数,第 0 个位置是前台进程组
*/

static const int beg = 1;
static int max, end;
static struct job **job;

/* empty: 1, otherwise: 0 */
int is_empty(struct job *job_list[], int len)
{
int i;
for (i = beg; i < len; i++) {
if (job_list[i])
return 0;
}
return 1;
}

void init_job(void)
{
/* Background */
max = 2;
end = 1;
job = malloc(sizeof(struct job *) * max);
if (!job) {
fprintf(stderr, "init_job: malloc error\n");
exit(-1);
}

/* Foreground */
job[0] = malloc(sizeof(struct job));
if (!job[0]) {
fprintf(stderr, "init_job: init foreground process failed!\n");
free_job();
exit(-1);
}
job[0]->command = NULL;
}

void free_job(void)
{
int i;
for (i = 0; i < end; i++)
free(job[i]);
free(job);
}

int add_job(pid_t pgid, int state, char *command, int len)
{
struct job *j = malloc(sizeof(struct job));
if (!j)
goto malloc_failed;
j->pgid = pgid;
j->state = state;
j->command = malloc(len);
if (!j->command)
goto malloc_failed;
memmove(j->command, command, len);

if (end != beg && is_empty(job, end))
end = beg;
if (end+1 == max) {
struct job **old_job = job;
int new_max = max * 3 / 2;
job = realloc(old_job, new_max*sizeof(struct job *));
if (!job) {
job = old_job;
free(j->command);
goto malloc_failed;
}
max = new_max;
}
job[end] = j;
end += 1;
printf("add_job: job list %d long now\n", end);

return 0;

malloc_failed:
perror("malloc");
fprintf(stderr, "add_job: malloc failed!\n");
free(j); /* 释放 NULL 是无害的 */
return -1;
}

int find_job(pid_t pgid)
{
int i;
for (i = beg; i < end; i++)
if (job[i] && job[i]->pgid == pgid)
return i;
return -1;
}

void delete_job(pid_t pgid)
{
int jid = find_job(pgid);
if (jid >= beg) {
free(job[jid]);
job[jid] = NULL;
}
}

void update_job(pid_t pgid, int state)
{
int jid = find_job(pgid);
if (beg <= jid && jid < end) {
job[jid]->state = state;
printf("[%d] %d %s\n", jid, (int)pgid, job[jid]->command);
} else {
printf("%d: No such process\n", (int)pgid);
}
}

pid_t get_pgid(int jid)
{
if (jid < end && job[jid])
return job[jid]->pgid;
return -1;
}

void print_job(int i)
{
printf("[%d] %d", i, (int)job[i]->pgid);
char *job_state;
if (job[i]->state == JOB_RUNNING)
job_state = "Running";
else if (job[i]->state == JOB_STOPPED)
job_state = "Stopped";
else if (job[i]->state == JOB_DONE)
job_state = "Done";
else
job_state = "Unkown";
printf(" %s %s\n", job_state, job[i]->command);
}

void print_job_by_pgid(pid_t pgid)
{
int jid = find_job(pgid);
print_job(jid);
}

void print_all_job(void)
{
int i;
for (i = beg; i < end; i++) {
if (!job[i])
continue;
print_job(i);
if (job[i]->state == JOB_DONE)
delete_job(job[i]->pgid);
}
}

void print_foreground(void)
{
if (job[0]->command)
printf("%s\n", job[0]->command);
}

void set_foreground(pid_t pgid, char *command, int len)
{
job[0]->pgid = pgid;
job[0]->state = JOB_RUNNING;
job[0]->command = malloc(len);
if (!job[0]->command) {
perror("malloc");
exit(-1);
}
memmove(job[0]->command, command, len);
}

pid_t foreground_pgid(void)
{
return job[0]->pgid;
}

void get_foreground_command(char *command)
{
int len = strlen(job[0]->command) + 1;
memmove(command, job[0]->command, len);
}

void move_to_background(pid_t pgid, int state, char *command, int len)
{
int jid = find_job(pgid);
if (jid < 0)
add_job(pgid, state, command, len);
else
update_job(pgid, state);
}

void move_to_foreground(pid_t pgid)
{
int jid = find_job(pgid);
if (jid >= beg)
*job[0] = *job[jid];
else
printf("%d: No such process\n", (int)pgid);
}
43 changes: 43 additions & 0 deletions exercise/ex8-26/job.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 8.26
*
* [email protected]
* 2013-7-14
*/

#ifndef __job_h
#define __job_h

#include <unistd.h>

#define JOB_RUNNING 0
#define JOB_STOPPED 1
#define JOB_DONE 2

struct job {
pid_t pgid; /* 进程组 ID */
int state; /* 作业状态 */
char *command; /* 运行作业的命令 */
};

extern void init_job(void);
extern int add_job(pid_t pgid, int state, char *command, int len);
extern void delete_job(pid_t pgid);
extern int find_job(pid_t pgid);
extern void free_job(void);
extern void update_job(pid_t pgid, int state);

extern pid_t get_pgid(int jid);

extern void print_job(int i);
extern void print_job_by_pgid(pid_t pgid);
extern void print_all_job(void);

extern pid_t foreground_pgid(void);
extern void get_foreground_command(char *command);
extern void print_foreground(void);
extern void set_foreground(pid_t pgid, char *command, int len);
extern void move_to_background(pid_t pgid, int state, char *command, int len);
extern void move_to_foreground(pid_t pgid);

#endif /* __job_h */
62 changes: 62 additions & 0 deletions exercise/ex8-26/random_fork.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* p521 -- code/ecf/rfork.c
*
* 下面的代码包含了一个暴露竞争的简便技巧
*
* 像 procmask2.c 那样的竞争难以发现,因为它们依赖于内核相关的调度决策。在一次
* fork() 调用之后,有些内核调度子进程先运行,而有些内核调度父进程先运行。如果你
* 要在后一种系统上运行 procmask1.c 的代码,它绝不会失败,无论你测试多少遍。但是
* 一旦在前一种系统上运行这段代码,那么竞争就会暴露出来,代码会失败。
*
* 下面的代码是一个 fork() 的包装函数,它随机地决定父进程和子进程执行的顺序。父进
* 程和子进程扔一枚硬币来决定谁会休眠,因而给另一个进程被调度的机会。
*
* 如果我们运行这个代码多次,那么我们就有极高的概率会测试到父子进程执行的两种顺序,
* 无论这个特定内核的调度策略是什么样子的。
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>

/* Sleep for a random period between [0, MAX_SLEEP] us. */
#define MAX_SLEEP 100000

/* Macro that maps val into the range [0, RAND_MAX] */
#define CONVERT(val) (((double)val)/(double)RAND_MAX)

pid_t random_fork(void)
{
static struct timeval time;
unsigned bool, secs;
pid_t pid;

/* Generate a different seed each time the function is called */
gettimeofday(&time, NULL);
srand(time.tv_usec);

/* Determine whether to sleep in parent of child and for how long */
bool = (unsigned)(CONVERT(rand()) + 0.5);
secs = (unsigned)(CONVERT(rand()) * MAX_SLEEP);

/* Call the real fork function */
if ((pid = fork()) < 0)
return pid;

/* Randomly decide to sleep in the parent or the child */
if (pid == 0) { /* Child */
if (bool) {
usleep(secs);
}
}
else { /* Parent */
if (!bool) {
usleep(secs);
}
}

/* Return the PID like a normal fork call */
return pid;
}
Loading

0 comments on commit 11959bf

Please sign in to comment.