Майкл Джонсон - Разработка приложений в среде Linux. Второе издание
- Название:Разработка приложений в среде Linux. Второе издание
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2007
- Город:Москва
- ISBN:978-5-8459-1143-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Майкл Джонсон - Разработка приложений в среде Linux. Второе издание краткое содержание
Книга известных профессионалов в области разработки коммерческих приложений в Linux представляет собой отличный справочник для широкого круга программистов в Linux, а также тех разработчиков на языке С, которые перешли в среду Linux из других операционных систем. Подробно рассматриваются концепции, лежащие в основе процесса создания системных приложений, а также разнообразные доступные инструменты и библиотеки. Среди рассматриваемых в книге вопросов можно выделить анализ особенностей применения лицензий GNU, использование свободно распространяемых компиляторов и библиотек, системное программирование для Linux, а также написание и отладка собственных переносимых библиотек. Изобилие хорошо документированных примеров кода помогает лучше усвоить особенности программирования в Linux.
Книга рассчитана на разработчиков разной квалификации, а также может быть полезна для студентов и преподавателей соответствующих специальностей.
Разработка приложений в среде Linux. Второе издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
162: if (!*src) {
163: freeJob(job);
164: fprintf(stderr, "ожидается символ после \\\n");
165: return 1;
166: }
167: /* двигаться дальше */
168: default:
169: *buf++=*src;
170: }
171:
172: src++;
173: }
174:
175: if (*prog->argv[argc]) {
176: argc++;
177: }
178: if (!argc) {
179: freeJob(job);
180: return 0;
181: }
182: prog->argv[argc]=NULL;
183:
184: if (!returnCommand) {
185: job->text = malloc(strlen(*commandPtr) + 1);
186: strcpy(job->text,*commandPtr);
187: } else {
188: /* Это оставляет хвостовые пробелы, что несколько излишне */
189:
190: count = returnCommand - *commandPtr;
191: job->text = malloc(count + 1);
192: strncpy(job->text,*commandPtr,count);
193: job->text[count] = '\0';
194: }
195:
196: *commandPtr = returnCommand;
197:
198: return 0;
199: }
200:
201: int runCommand(struct jobnewJob, struct jobSet *jobList,
202: intinBg) {
203: struct job *job;
204:
205: /* обходной путь "вручную" - мы не используем fork(),
206: поэтому не можем легко реализовать фоновый режим */
207: if (!strcmp(newJob.progs[0].argv[0], "exit")) {
208: /* это должно вернуть реальный код возврата */
209: exit(0);
210: } else if(!strcmp(newJob.progs[0].argv[0], "jobs")) {
211: for (job = jobList->head; job; job = job->next)
212: printf(JOB_STATUS_FORMAT, job->jobId, "Работаю",
213: job->text);
214: return 0;
215: }
216:
217: /* у нас пока только одна программа на дочернее задание,
218: потому это просто */
219: if (!(newJob.progs[0].pid = fork())) {
220: execvp(newJob.progs[0].argv[0],newJob.progs[0].argv);
221: fprintf(stderr, "exec() для %s потерпела неудачу: %s\n",
222: newJob.progs[0].argv[0],
223: strerror(errno));
224: exit(1);
225: }
226:
227: /* поместить дочернюю программу в отдельную группу процессов */
228: setpgid(newJob.progs[0].pid,newJob.progs[0].pid);
229:
230: newJob.pgrp = newJob.progs[0].pid;
231:
232: /* найти идентификатор для задания */
233: newJob.jobld = 1;
234: for (job = jobList->head; job; job = job->next)
235: if (job->jobId >= newJob.jobId)
236: newJob.jobId = job->jobId+1;
237:
238: /* задание для списка заданий */
239: if (!jobList->head) {
240: job = jobList->head = malloc(sizeof(*job));
241: } else {
242: for (job = jobList->head; job->next; job = job->next);
243: job->next = malloc(sizeof(*job));
244: job = job->next;
245: }
246:
247: *job = newJob;
248: job->next = NULL;
249: job->runningProgs = job->numProgs;
250:
251: if (inBg) {
252: /* мы не ждем завершения фоновых заданий - добавить
253: в список фоновых заданий и оставить в покое */
254:
255: printf("[%d]%d\n", job->jobId,
256: newJob.progs[newJob.numProgs-1].pid);
257: } else {
258: jobList->fg=job;
259:
260: /* переместить новую группу процессов на передний план */
261:
262: if (tcsetpgrp(0,newJob.pgrp))
263: perror("tcsetpgrp");
264: }
265:
266: return 0;
267: }
268:
269: void removeJob(struct jobSet *jobList, struct job *job) {
270: struct job *prevJob;
271:
272: freeJob(job);
273: if (job == jobList->head) {
274: jobList->head=job->next;
275: } else {
276: prevJob = jobList->head;
277: while (prevJob->next != job) prevJob = prevJob->next;
278: prevJob->next=job->next;
279: }
280:
281: free(job);
282: }
283:
284: /* Проверить, завершился ли какой-то из фоновых процессов -
285: если да, выяснить, почему и определить, завершилось ли задание */
286: void checkJobs(struct jobSet *jobList) {
287: struct job *job;
288: pid_t childpid;
289: int status;
290: int progNum;
291:
292: while ((childpid = waitpid(-1, &status, WNOHANG))>0) {
293: for (job = jobList->head;job;job = job->next) {
294: progNum = 0;
295: while (progNumnumProgs &&
296: job->progs[progNum].pid != childpid)
297: progNum++;
298: if (progNumnumProgs) break;
299: }
300:
301: job->runningProgs--;
302: job->progs[progNum].pid = 0;
303:
304: if (!job->runningProgs) {
305: printf(JOB_STATUS_FORMAT,job->jobId,"Готово",
306: job->text);
307: removeJob(jobList, job);
308: }
309: }
310:
311: if (childpid == -1 && errno!= ECHILD)
312: perror("waitpid");
313: }
314:
315: int main(int argc, const char **argv) {
316: char command [MAX_COMMAND_LEN + 1];
317: char *nextCommand = NULL;
318: struct jobSetjobList = {NULL, NULL};
319: struct jobnewJob;
320: FILE *input = stdin;
321: int i;
322: int status;
323: int inBg;
324:
325: if (argc>2) {
326: fprintf(stderr,"Непредвиденные аргументы; использование: ladsh1 "
327: "<���команды>\n");
328: exit(1);
329: } else if (argc == 2) {
330: input = fopen(argv[1], "r");
331: if (!input) {
332: perror("fopen");
333: exit(1);
334: }
335: }
336:
337: /* не обращать внимания на этот сигнал; он только вводит
338: в заблуждение и не имеет особого значения для оболочки */
339: signal(SIGTTOU, SIG_IGN);
340:
341: while(1) {
342: if (!jobList.fg) {
343: /* нет заданий переднего плана */
344:
345: /* проверить, завершились ли какие-то фоновые процессы */
346: checkJobs(&jobList);
347:
348: if (!nextCommand) {
349: if (getCommand(input, command)) break;
350: nextCommand=command;
351: }
352:
353: if (!parseCommand(&nextCommand, &newJob, &inBg) &&
354: newJob.numProgs) {
355: runCommand(newJob,&jobList,inBg);
356: }
357: } else {
358: /* задание выполняется на переднем плане; ждать завершения */
359: i = 0;
360: while (!jobList.fg->progs[i].pid) i++;
361:
362: waitpid(jobList.fg->progs[i].pid,&status,0);
363:
364: jobList.fg->runningProgs--;
365: jobList.fg->progs[i].pid=0;
366:
367: if (!jobList.fg->runningProgs) {
368: /* дочернее завершилось */
369:
370: removeJob(&jobList, jobList.fg);
371: jobList.fg = NULL;
372:
373: /* переместить оболочку на передний план */
374: if (tcsetpgrp(0, getpid()))
375: perror("tcsetpgrp");
376: }
377: }
378: }
379:
380: return 0;
381: }
Эта версия не делает ничего, кроме запуска внешней программы с аргументами, поддержки комментариев стиля #
(все, что следует за символом #
, игнорируется), и позволяет программам выполняться в фоновом режиме. Она работает как интерпретатор простых сценариев оболочки, написанных в нотации #!
, но ничего сверх этого не делает. Она разработана в качестве имитации обычного интерпретатора оболочки, используемого в системах Linux, несмотря на то, что в значительной степени упрощена.
Прежде всего, взглянем на структуры данных, которые здесь используются. На рис. 10.2 показаны структуры данных, используемые в ladsh1.с
для отслеживания запускаемых дочерних процессов, на примере применения программы grep
в фоновом режиме и links
— в режиме переднего плана, struct jobSet
описывает набор функционирующих заданий. Он содержит связный список заданий и указатель на текущее задание, выполняемое на переднем плане. Если такового нет, то указатель равен NULL
, ladsh1.с
использует struct jobSet
для того, чтобы отслеживать задания, выполняемые в данный момент в фоновом режиме.
Интервал:
Закладка: