Дырявые абстракции, или К слову об юникс-си-программизмах

Персональный блог одноименного форумчанина. Человека и парохода, не побоюсь этого сравнения :)

Модератор: tyomitch

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Дырявые абстракции, или К слову об юникс-си-программизмах

Сообщение tyomitch » 08.07.2006 (Сб) 21:19

* У меня возникла нужда в программе, которая ограничивала бы время работы другой программы заданным числом секунд -- примерно как time(1), только наоборот: time получает время работы программы, а мне надо его задавать. Как ни удивительно для программы, одновременно тривиально простой и практически ценной, в стандартной поставке FreeBSD я такую программу найти не смог. (Вопрос №1: я что-то проглядел, или её там действительно нет?) Желания извращаться с мегазаумными конструкциями на основе sleep && kill & тоже не было.

* Вот как такая программа выглядела бы в Windows: (проверено в VC6)
Код: Выделить всё
#include <stdio.h>
#include <process.h>
#include <windows.h>

const char* name = "settime";

int main (int argc, char *argv[]) {
  char* end; unsigned count; int status;
  int pid;  // на самом деле хендл

  if (argc <3 || (count = strtoul(argv[1], &end, 10), *end)) {
    printf("Usage: %s count command parameters...\n", name); return 1;
  }

  if ((pid =_spawnvp(_P_NOWAIT, argv[2], argv+2)) <0) {
    printf("%s: cannon spawn %s\n", name, argv[2]);
    return -1;
  }

  if (WaitForSingleObject(pid, count*1000) == WAIT_TIMEOUT)
    TerminateProcess(pid, 0);
  GetExitCodeProcess(pid, &status);
  return status;
}

Ничего хитрого: последовательный вызов _spawnvp, WaitForSingleObject и TerminateProcess либо GetExitCodeProcess. (На чистом WinAPI вышло бы лишь чуть-чуть сложнее, за счёт самостоятельного сбора-разбора командной строки.)

* Но вот во FreeBSD сразу же начинаются проблемы из-за вынесенных в заголовок дырявых интерфейсов системных библиотек. (Когда маны пестрят фразами типа "этой функции совсем не место в этой библиотеке, но все уже привыкли", как про kvm_getprocs(3), -- это явный признак проекта, пущенного на самотёк.)

Прежде всего, FreeBSD предоставляет три способа запустить новый процесс: fork(2) со товарищи, system(3) и popen(3). (Вопрос №2: я ничего не забыл?) Про fork я уже писал: она создаёт копию текущего процесса, и возвращает родителю PID ребёнка, а ребёнку -- 0, после чего они продолжают выполняться с одного места. system создаёт ребёнка, ждёт его завершения, и возвращает код его возврата, а popen создаёт ребёнка со входом и/или выходом, перенаправленным в трубу, и возвращает хэндл этой трубы.

Предоставляемой в VC функцией spawn, и по-моему, совершенно естественной возможности запустить ребёнка, и, не дожидаясь его завершения, получить его PID -- в стандартных библиотеках нет. Неужели это настолько необычная задача, что для её решения нужна конструкция switch(pid=fork()) {case -1: /* неудача */ case 0: exec(...); } /* теперь pid заполнен */ :?: (Это вопрос №3)

Следующая оплеуха от FreeBSD -- полное отсутствие функций ожидания с таймаутом. Чтобы его реализовать, надо заводить будильник (alarm(3)) на нужное время, и по его сигналу каким-то образом ожидание прерывать. Будильник один на весь процесс, поэтому если им попользовалась какая-то из системных функций (например, sleep(3)) -- он сбрасывается. Вопрос №4: почему на то, что в Windows реализуется одним вызовом WaitForSingleObject, во FreeBSD нужно тратить полстраницы среднеизощрённого кода?

* Вот что у меня в результате получилось. Оно даже работает; однако, сравните длину с версией для Windows.
Код: Выделить всё
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>

const char* name = "settime";
unsigned pid;

static void sig_handler(int sig) {
  kill(pid, SIGTERM);
}

int main (int argc, char *argv[]) {
  char* end; unsigned count; int status;

  if (argc <3 || (count = strtoul(argv[1], &end, 10), *end)) {
    printf("Usage: %s count command parameters...\n", name); return 1;
  }

  switch (pid =fork()) {
  case -1:
    printf("%s: cannot fork\n", name);
    return -1;
  case 0:
    execvp(argv[2], argv+2);
    printf("%s: cannon exec %s\n", name, argv[2]);
    return -2;
  }

  signal(SIGALRM, sig_handler);
  alarm(count);
  waitpid(pid, &status, 0);
  return status;
}

Если такая программа вам нужна под одной из двух представленных ОС, можете пользоваться :-)
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 11.07.2006 (Вт) 3:07

Перечитывая текст, обнаружил, что забыл дописать главное: и где же здесь дырявые абстрации?

Имелось в виду, что юникс-си-программист вынужден писать свою функцию для запуска процессов, свою функцию для ожидания с таймаутом и т.д. -- по сути, дописывая эту недо-ОС. По сравнению с ней, Windows стократ дружественнее не только к пользователю, но и к программисту.

Под девизом внесения в ОС только самого необходимого и ортогонального (юникс-си-программисты хвастаются: в WinAPI стотыщ функций, а у них всего сотня-другая) юниксоиды вынудили сами себя решать все сколько-нибудь небазовые задачи заново в каждой программе. Расплодились кучи несовместимых библиотек, предоставляющих такие подпрограммки -- функциональность которых в Windows включена в состав ОС. Зато в Unix открытость, гибкость, и широко растопыренные пальцы :-|
Изображение

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 11.07.2006 (Вт) 9:04

Собственно, за что боролись, на то и напоролись, не вижу тут никакого криминала. Кому-то проще написать свою функцию, чем запоминать десяток чужих. Кроме того большинство юниксоидов просто пользуют систему, а не пишут (хотя не знаю, есть ли тут отличие), и в юниксоиды идут не те люди, что спрашивают "как достать текст с хтмл-страницы". Возможно то, что ты рожал в спазмах отвращения, для них не напряжней, чем для тебя WaitForSingleObject.
Лучший способ понять что-то самому — объяснить это другому.

Sebas
Неуловимый Джо
Неуловимый Джо
Аватара пользователя
 
Сообщения: 3626
Зарегистрирован: 12.02.2002 (Вт) 17:25
Откуда: столько наглости такие вопросы задавать

Сообщение Sebas » 11.07.2006 (Вт) 10:12

И, наверное, не надо показушничать. Дырявая абстракция - всего лишь ИНКАПСУЛЯЦИЯ не более) PR решает?
- Я никогда не понимал, почему они приходят ко мне чтобы умирать?

sebas<-@->mail.ru

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 11.07.2006 (Вт) 12:38

При чём здесь показушничанье? я высказал своё мнение, и подкрепил его конкретными аргументами.
Изображение


Вернуться в Tyomitch

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 11

    TopList