Operating system: IBM AIX 5.3
Compiler: xlc
Hello Everyone
I have a project that using C to process some files using multi-processes. The number of sub-processes are mainly depends on the the number of incoming files and the number of current running processes. I need a reliable method to count on how many sub-processes are running at background.
By comparing the efficiency, directly reading /proc directory may have better performance than invoking popen() to execute $ ps -ef | grep blah.
I wrote a function to read psinfo in /proc/pid/psinfo and compare the arugments.
Pseudo code is as follow:
int count = 0;
dp = opendir("/proc");
while (readdir_r(...))
{
if (dir is not a process)
return -1;
if (dir's owner is not current user)
return -2;
if (failed to open "/proc/[pid]/psinfo")
return -3;
if (failed to read "/proc/[pid]/psinfo")
return -4;
if (process's name matches the given pname)
count += 1;
}
return count;
The function generally runs perfectly at single call. However, it returns -2 or -3 or even wrong counts when embedded in while loop.
The function failed to read the attribute of /proc/pid randomly. It tells No such file or directory.
There is also a small chance to get wrong counts at the end. There seems to be an extra process with certain pid but disappeared when printing the current processes using ps.
I think there is any change were made when reading from sub-directory rapidly after parent directory were being listed.
Is there any thing I made wrong or is there any method to avoid the race condition?
Come extra information about psinfo in AIX
http://www-01.ibm.com/support/knowledgecenter/ssw_aix_53/com.ibm.aix.files/doc/aixfiles/proc.htm%23files-proc?lang=en[233]
Here is the full source code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/procfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int countProcess(char *pname)
{
DIR *dir;
int fd;
int pid;
int uid;
int pcounter = 0;
struct psinfo pinfo;
struct dirent entry;
struct dirent *result;
struct stat fsstat;
char path[256];
char process_path[256];
/* Open the /proc directory */
if ((dir = opendir("/proc")) == NULL)
{
return -1;
}
/* Retrieve the current user id */
uid = getuid();
/* Walk through the /proc dir */
for (readdir_r(dir, &entry, &result); result != NULL; readdir_r(dir, &entry, &result))
{
/* See if this is a process, e.g., the dirname is a number
If not, then start off again
*/
if ((pid = atoi(entry.d_name)) == 0)
{
continue;
}
/* Get the attributes of process dir */
snprintf(process_path, sizeof(process_path), "/proc/%s", entry.d_name);
if (stat(process_path, &fsstat) == -1)
{
closedir(dir);
return -2;
}
/* Verify if the process runs by current user
If not, then start off again
*/
if (fsstat.st_uid != uid)
{
continue;
}
/* Open and read from psinfo file */
snprintf(path, sizeof(path), "/proc/%s/psinfo", entry.d_name);
if ((fd = open(path, O_RDONLY)) < 0)
{
close(fd);
closedir(dir);
return -3;
}
if (read(fd, &pinfo, sizeof(pinfo)) < 0)
{
close(fd);
closedir(dir);
return -4;
}
/* String comparison, if same, increase the counter */
if (!strcmp(pinfo.pr_psargs, pname))
{
pcounter++;
}
close(fd);
}
/* returns counter */
closedir(dir);
return pcounter;
}
Update 13/Jan/2015
Thanks to CoreyStup. The race condition can be bypassed by getprocs() function provided in procinfo.h
Here is the code for the solution
#include <stdio.h>
#include <unistd.h>
#include <procinfo.h>
#include <sys/types.h>
int countProcess(const char *pname)
{
struct procsinfo pinfo;
pid_t pid = 0;
uid_t uid;
char args[256];
int index;
int pcounter = 0;
memset(args, 0, sizeof(args));
uid = getuid();
/* Get procsinfo from internal API */
while (0 < getprocs(&pinfo, (int)sizeof(struct procsinfo), NULL, 0, &pid, 1))
{
/* Skip the process that doesn't belong to current user */
if (pinfo.pi_uid != uid)
{
continue;
}
/* Get process arguments */
if (getargs(&pinfo, sizeof(struct procsinfo), args, sizeof(args)) != 0)
{
return -1;
}
/* getargs returns the args list seperated by 0, we need to use space to replace 0 */
for (index = 0; index < 256 - 1 && !(args[index] == 0 && args[index + 1] == 0); index++)
{
if (args[index] == 0)
{
args[index] = ' ';
}
}
if (!strncmp(args, pname, strlen(pname)))
{
pcounter++;
}
}
return pcounter;
}
Try using getprocs(). I find it works better than shelling out with /proc or ps.
I gave an example here: Need help in getting the process name based on the pid in aix
Related
I have recently started programming in UNIX environment. I need to write a program which creates an empty file with name and size given in the terminal using this commands
gcc foo.c -o foo.o
./foo.o result.txt 1000
Here result.txt means the name of the newly created file, and 1000 means the size of the file in bytes.
I know for sure that lseek function moves the file offset, but the trouble is that whenever I run the program it creates a file with a given name, however the size of the file is 0.
Here is the code of my small program.
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
int main(int argc, char **argv)
{
int fd;
char *file_name;
off_t bytes;
mode_t mode;
if (argc < 3)
{
perror("There is not enough command-line arguments.");
//return 1;
}
file_name = argv[1];
bytes = atoi(argv[2]);
mode = S_IWUSR | S_IWGRP | S_IWOTH;
if ((fd = creat(file_name, mode)) < 0)
{
perror("File creation error.");
//return 1;
}
if (lseek(fd, bytes, SEEK_SET) == -1)
{
perror("Lseek function error.");
//return 1;
}
close(fd);
return 0;
}
If you aren't allowed to use any other functions to assist in creating a "blank" text file, why not change your file mode on creat() then loop-and-write:
int fd = creat(file_name, 0666);
for (int i=0; i < bytes; i++) {
int wbytes = write(fd, " ", 1);
if (wbytes < 0) {
perror("write error")
return 1;
}
}
You'll want to have some additional checks here but, that would be the general idea.
I don't know whats acceptable in your situation but, possibly adding just the write() call after lseek() even:
// XXX edit to include write
if ((fd = creat(file_name, 0666)) < 0) {
perror("File creation error");
//return 1;
}
// XXX seek to bytes - 1
if (lseek(fd, bytes - 1, SEEK_SET) == -1) {
perror("lseek() error");
//return 1;
}
// add this call to write a single byte # position set by lseek
if (write(fd, " ", 1) == -1) {
perror("write() error");
//return 1;
}
close(fd);
return 0;
I am working on reader-writer problem. Algorithm wise, i believe the solution is ok. The only problem that I am facing is opening multiple readers/writer windows using xterm. When I run the program it goes into an infinite loop and it crashed the whole system. It also open multiple xterm windows. It might be silly and simple, but I just don't seem to be able to figure out why? I've been thinking about this since yesterday. How do i fix this problem? The suspected area of conflict is highlighted with ** comments...
#include <unistd.h> /* Symbolic Constants */
#include <sys/types.h> /* Primitive System Data Types */
#include <errno.h> /* Errors */
#include <stdio.h> /* Input/Output */
#include <stdlib.h> /* General Utilities */
#include <pthread.h> /* POSIX Threads */
#include <string.h> /* String handling */
#include <semaphore.h> /* Semaphore */
//Global Variablels
int rc = 0;
int wc = 0;
sem_t m1, m2, m3, w, r; //Semphore
int reader() {
sem_wait(&m3);
sem_wait(&r);
sem_wait(&m1);
rc++;
if(rc == 1) sem_wait(&w);
sem_post(&m1);
sem_post(&r);
sem_post(&m3);
system("xterm -e ./read");
//execlp("xterm", "-e", "./ahor2r", NULL);
sem_wait(&m1);
rc--;
if(rc == 0) sem_post(&w);
sem_post(&m1);
return 0;
}
int writer() {
sem_wait(&m2);
wc++;
if(wc == 1) sem_wait(&r);
sem_post(&m2);
sem_wait(&w);
//system("xterm -e ./write"); //writing is performed
execlp("xterm", "-e", "./ahor2w", NULL);
sem_post(&w);
sem_wait(&m2);
wc--;
if(wc == 0) sem_post(&r);
sem_post(&m2);
return 0;
}
int main() {
int ch;
sem_init(&m1, 0, 1);
sem_init(&m2, 0, 1);
sem_init(&m3, 0, 1);
sem_init(&w, 0, 1);
sem_init(&r, 0, 1);
/*****************************************************************************
**********infinite loop*******************************************************/
while(1) {
printf("\n\nEnter your option\n\n1> Create Reader\n2> Create Writer\n 3> Exit\n\t");
scanf("%d", &ch);
if(ch == 1)
switch(fork()) {
case -1:
perror("Cannot fork a new reader process\n");
break;
case 0:
reader();
}
else if (ch == 2)
switch(fork()) {
case -1:
perror("Cannot fork a new reader process\n");
break;
case 0:
writer();
}
else if (ch == 3) {
sem_destroy(&m1);
sem_destroy(&m2);
sem_destroy(&m3);
sem_destroy(&w);
sem_destroy(&r);
return 0;
}
else printf("INVALID OPTION - no action taken\n");
}
/*****************************************************************************
*****************************************************************************/
return 0;
}
You have two big errors:
You don't create your semaphores in shared memory. So each process gets its own copy of the semaphores, which makes no sense.
You don't create process-shared semaphores. The 0 in sem_init means that the semaphores will not be shared between processes. But fork creates new processes.
If pshared has the value 0, then the semaphore is shared between the threads of a process[.] If pshared is nonzero, then the semaphore is shared between processes, and should be located in a region of shared memory (see shm_open(3), mmap(2), and shmget(2)).
I am trying to make http streaming program.
So I follow this code at this.
However, when i decode, only one frame is decoded.
I think I need call back function.
Do you know how to make a call back function?
I know 'asf' packet's call back function is like int read_data(void *opaque, char *buf, int buf_size)
But the other formats(mp3, ogg, aac, ..) doesn't work..
Please help me.
Any advice or comment are very appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
int main(int argc, char **argv)
{
static AVInputFormat *file_iformat;
static AVFormatContext *pFormatCtx;
AVFormatParameters params;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
const char url[] = "http://listen.radionomy.com/feelingfloyd";
avcodec_register_all();
avdevice_register_all();
av_register_all();
av_log_set_level(AV_LOG_VERBOSE);
file_iformat = av_find_input_format("mp3"); /* mp3 demuxer */
if (!file_iformat)
{
fprintf(stderr, "Unknown input format: %s\n", &url[0]);
exit(1);
}
//file_iformat->flags |= AVFMT_NOFILE; /* ??? */
params.prealloced_context = 0;
if (av_open_input_file(&pFormatCtx, &url[0], file_iformat, 0, ¶ms) != 0)
{
fprintf(stderr, "err 1\n");
exit(2);
}
/* poulates AVFormatContex structure */
if (av_find_stream_info(pFormatCtx) < 0)
{
fprintf(stderr, "err 2\n");
}
/* sanity check (1 stream) */
if (pFormatCtx->nb_streams != 1 &&
pFormatCtx->streams[0]->codec->codec_type != AVMEDIA_TYPE_AUDIO)
{
fprintf(stderr, "err 3\n");
}
pCodecCtx = pFormatCtx->streams[0]->codec;
/* find decoder for input audio stream */
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL)
{
fprintf(stderr, "err 4: unsupported codec\n");
}
if (pCodec->capabilities & CODEC_CAP_TRUNCATED)
pCodecCtx->flags |= CODEC_FLAG_TRUNCATED;
if (avcodec_open(pCodecCtx, pCodec) < 0)
{
fprintf(stderr, "err 5\n");
}
{
uint8_t *pAudioBuffer;
AVPacket pkt;
int ret;
int data_size = 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE;
av_init_packet(&pkt);
//pkt.data=NULL;
//pkt.size=0;
//pkt.stream_index = 0;
pAudioBuffer = av_malloc(data_size * sizeof(int16_t));
while (av_read_frame(pFormatCtx, &pkt) == 0) {
//data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
ret = avcodec_decode_audio3(pFormatCtx->streams[pkt.stream_index]->codec,
(int16_t *)pAudioBuffer, &data_size, &pkt);
/* got an error (-32) here */
if (ret < 0) {
av_strerror(ret, (char *)pAudioBuffer, data_size);
fprintf(stderr, "err 6 (%s)\n", pAudioBuffer);
break;
}
printf("size=%d, stream_index=%d |ret=%d data_size=%d\n",
pkt.size, pkt.stream_index, ret, data_size);
av_free_packet(&pkt);
}
av_free(pAudioBuffer);
}
avcodec_close(pCodecCtx);
av_close_input_file(pFormatCtx);
return 0;
}
I figure out this problem by using av_open_input_file.
I got a this problem when I made a iphone app that play http audio streaming. And the above code didn't work. only played just some of audio frame. it also means there are so many buffering.
However After using iphone audio callback function and large audio buffer, it works fine.
Those who are curious about the final code send me a messege.
What would be the best way to do this in the C programming language?
find fileName
Look up the POSIX function nftw(). It is designed as a 'new file tree walk' function.
There's a related but not immediately as useful function scandir() which you might use. The selection function might be used to invoke a recursive scan on sub-directories, for example, but nftw() is probably more appropriate.
You could call find from a forked child process and get back find's output from a pipe:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFSIZE 1000
int main(void) {
int pfd[2], n;
char str[BUFSIZE + 1];
if (pipe(pfd) < 0) {
printf("Oups, pipe failed. Exiting\n");
exit(-1);
}
n = fork();
if (n < 0) {
printf("Oups, fork failed. Exiting\n");
exit(-2);
} else if (n == 0) {
close(pfd[0]);
dup2(pfd[1], 1);
close(pfd[1]);
execlp("find", "find", "filename", (char *) 0);
printf("Oups, execlp failed. Exiting\n"); /* This will be read by the parent. */
exit(-1); /* To avoid problem if execlp fails, especially if in a loop. */
} else {
close(pfd[1]);
while ((n = read(pfd[0], str, BUFSIZE)) > 0) {
str[n] = '\0';
printf("%s", str);
}
close(pfd[0]);
wait(&n); /* To avoid the zombie process. */
if (n != 0) {
printf("Oups, find or execlp failed.\n");
}
}
}
That's a complex topic. Have a look at the GNU libc documentation. Then try to scan the current directory using scandir. If that works, you can implement a recursive version, assuming you are talking about the UNIX find command and want to do recursive search for file names.
I need to use Signal to write UNIX Interprocess communication program in C. I want a parent process and child process to write to a same file.
The result only show parent written text. I can use either BSD or System V. Please help
#include <stdio.h> /* basic I/O routines. */
#include <unistd.h> /* define fork(), etc. */
#include <sys/types.h> /* define pid_t, etc. */
#include <sys/wait.h> /* define wait(), etc. */
#include <signal.h>
int myFlag = 0;
void myHandler(int);
int child_pid;
int main()
{
//oldmask = sigblock(sigmask(SIGUSR1));
sighold(SIGUSR1);
sighold(SIGINT);
/* critical region */
signal (SIGUSR1, myHandler);
sigrelse(SIGUSR1);
sigrelse(SIGINT);
child_pid = fork();
if (child_pid==0) {
for ( ; ; ) {
while(myFlag == 0)
sigpause(0);
sigblock (sigmask(SIGUSR1));
myFlag = 0;
FILE *fp=fopen("test","w");
fwrite("child",1,6,fp);
fclose(fp);
kill(getppid(),SIGUSR1);
}
}
if (child_pid>0){
FILE *fp;
fp=fopen("test","w");
fwrite("parent",1,6,fp);
fclose(fp);
for ( ; ; ) {
while(myFlag == 0)
sigpause(0);
sigblock (sigmask(SIGUSR1));
myFlag = 0;
fp=fopen("test","w");
fwrite("parent",1,6,fp);
fclose(fp);
}
kill(child_pid, SIGUSR1);
//kill ()-child_pid ;
}
exit(0);
}
void myHandler(int sigNo) {
myFlag = 1;
//signal (SIGUSR1, myHandler);
}
You should start by opening the file in append mode rather than write mode:
fp = fopen("test", "a");
That will position the write position of fp at the end of file rather than the beginning. When you open with "w", you truncate the file and start writing from position 0:
w or wb
Truncate to zero length or create file for writing.
Then you might want to think about file locking to keep the two processes from writing to the file at the same time.
Also, your child process writes out the nul terminator:
fwrite("child", 1, 6, fp);
but your parent process doesn't:
fwrite("parent", 1, 6, fp);
That may or may not be your intention but it does look odd.
Your logic is flawed. The parent process does not signal the child process before it waits for the child process to signal it. The child process waits for the parent process to signal it before writing the file and signaling the parent process.
This means after you write the file in the parent both the parent and child are stuck in busy loops waiting for the other one to do something.
Also, while I don't think this is a problem in your code since the call to sigpause(0); should cause the compiler to believe that global variables may have changed and need to be reloaded, in other situations you might want to declare myFlag as volatile int myFlag;. This forces the compiler to read or write its value from memory every time you reference it.
Lastly, of course, your programs will simply re-write over the same bytes repeatedly because you open the files in "w" (write) mode instead of "a" (append) mode.
Here's a program that accomplishes what you want using POSIX standard calls and techniques instead of the old deprecated obsolete calls you were using:
#include <stdio.h> /* basic I/O routines. */
#include <unistd.h> /* define fork(), etc. */
#include <sys/types.h> /* define pid_t, etc. */
#include <sys/wait.h> /* define wait(), etc. */
#include <signal.h>
#include <stdlib.h>
volatile sig_atomic_t myFlag = 0;
void myHandler(int);
int child_pid;
int main()
{
signal (SIGUSR1, myHandler);
child_pid = fork();
if (child_pid==0) {
for ( ; ; ) {
while(myFlag == 0)
;
{
sigset_t oldmask;
sigset_t usr1;
sigemptyset(&oldmask);
sigemptyset(&usr1);
sigaddset(&usr1, SIGUSR1);
sigprocmask(SIG_BLOCK, &usr1, &oldmask);
myFlag = 0;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
FILE *fp=fopen("test","a");
fwrite("child\n",1,6,fp);
fclose(fp);
kill(getppid(),SIGUSR1);
}
}
if (child_pid>0){
FILE *fp;
fp=fopen("test","a");
fwrite("parent\n",1,7,fp);
fclose(fp);
for ( ; ; ) {
kill(child_pid, SIGUSR1);
//kill ()-child_pid ;
while(myFlag == 0)
;
{
sigset_t oldmask;
sigset_t usr1;
sigemptyset(&oldmask);
sigemptyset(&usr1);
sigaddset(&usr1, SIGUSR1);
sigprocmask(SIG_BLOCK, &usr1, &oldmask);
myFlag = 0;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
fp=fopen("test","a");
fwrite("parent\n",1,7,fp);
fclose(fp);
}
}
exit(0);
}
void myHandler(int sigNo) {
myFlag = 1;
//signal (SIGUSR1, myHandler);
}