~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to libs/ksysguard/processcore/processes_linux_p.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  This file is part of the KDE project
 
2
 
 
3
    Copyright (C) 2007 John Tapsell <tapsell@kde.org>
 
4
 
 
5
    This library is free software; you can redistribute it and/or
 
6
    modify it under the terms of the GNU Library General Public
 
7
    License as published by the Free Software Foundation; either
 
8
    version 2 of the License, or (at your option) any later version.
 
9
 
 
10
    This library is distributed in the hope that it will be useful,
 
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
    Library General Public License for more details.
 
14
 
 
15
    You should have received a copy of the GNU Library General Public License
 
16
    along with this library; see the file COPYING.LIB.  If not, write to
 
17
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
18
    Boston, MA 02110-1301, USA.
 
19
 
 
20
*/
 
21
 
 
22
#include "processes_local_p.h"
 
23
#include "process.h"
 
24
 
 
25
#include <klocale.h>
 
26
 
 
27
#include <QFile>
 
28
#include <QHash>
 
29
#include <QSet>
 
30
#include <QByteArray>
 
31
#include <QTextStream>
 
32
 
 
33
//for sysconf
 
34
#include <unistd.h>
 
35
//for kill and setNice
 
36
#include <errno.h>
 
37
#include <sys/types.h>
 
38
#include <signal.h>
 
39
#include <sys/resource.h>
 
40
#include <dirent.h>
 
41
#include <stdlib.h>
 
42
//for ionice
 
43
#include <sys/ptrace.h>
 
44
#include <asm/unistd.h>
 
45
//for getsched
 
46
#include <sched.h>
 
47
 
 
48
#define PROCESS_BUFFER_SIZE 1000
 
49
 
 
50
/* For ionice */
 
51
extern int sys_ioprio_set(int, int, int);
 
52
extern int sys_ioprio_get(int, int);
 
53
 
 
54
#define HAVE_IONICE
 
55
/* Check if this system has ionice */
 
56
#if !defined(SYS_ioprio_get) || !defined(SYS_ioprio_set)
 
57
/* All new kernels have SYS_ioprio_get and _set defined, but for the few that do not, here are the definitions */
 
58
#if defined(__i386__)
 
59
#define __NR_ioprio_set         289
 
60
#define __NR_ioprio_get         290
 
61
#elif defined(__ppc__) || defined(__powerpc__)
 
62
#define __NR_ioprio_set         273
 
63
#define __NR_ioprio_get         274
 
64
#elif defined(__x86_64__)
 
65
#define __NR_ioprio_set         251
 
66
#define __NR_ioprio_get         252
 
67
#elif defined(__ia64__)
 
68
#define __NR_ioprio_set         1274
 
69
#define __NR_ioprio_get         1275
 
70
#else
 
71
#ifdef __GNUC__
 
72
#warning "This architecture does not support IONICE.  Disabling ionice feature."
 
73
#endif
 
74
#undef HAVE_IONICE
 
75
#endif
 
76
/* Map these to SYS_ioprio_get */
 
77
#define SYS_ioprio_get                __NR_ioprio_get
 
78
#define SYS_ioprio_set                __NR_ioprio_set
 
79
 
 
80
#endif /* !SYS_ioprio_get */
 
81
 
 
82
/* Set up ionice functions */
 
83
#ifdef HAVE_IONICE
 
84
#define IOPRIO_WHO_PROCESS 1
 
85
#define IOPRIO_CLASS_SHIFT 13
 
86
 
 
87
/* Expose the kernel calls to userspace via syscall
 
88
 * See man ioprio_set  and man ioprio_get   for information on these functions */
 
89
static int ioprio_set(int which, int who, int ioprio)
 
90
{
 
91
  return syscall(SYS_ioprio_set, which, who, ioprio);
 
92
}
 
93
 
 
94
static int ioprio_get(int which, int who)
 
95
{
 
96
  return syscall(SYS_ioprio_get, which, who);
 
97
}
 
98
#endif
 
99
 
 
100
 
 
101
 
 
102
 
 
103
namespace KSysGuard
 
104
{
 
105
 
 
106
  class ProcessesLocal::Private
 
107
  {
 
108
    public:
 
109
      Private() { mProcDir = opendir( "/proc" );}
 
110
      ~Private();
 
111
      inline bool readProcStatus(const QString &dir, Process *process);
 
112
      inline bool readProcStat(const QString &dir, Process *process);
 
113
      inline bool readProcStatm(const QString &dir, Process *process);
 
114
      inline bool readProcCmdline(const QString &dir, Process *process);
 
115
      inline bool getNiceness(long pid, Process *process);
 
116
      inline bool getIOStatistics(const QString &dir, Process *process);
 
117
      QFile mFile;
 
118
      char mBuffer[PROCESS_BUFFER_SIZE+1]; //used as a buffer to read data into
 
119
      DIR* mProcDir;
 
120
  };
 
121
 
 
122
ProcessesLocal::Private::~Private()
 
123
{
 
124
    closedir(mProcDir);
 
125
}
 
126
 
 
127
ProcessesLocal::ProcessesLocal() : d(new Private())
 
128
{
 
129
 
 
130
}
 
131
 
 
132
bool ProcessesLocal::Private::readProcStatus(const QString &dir, Process *process)
 
133
{
 
134
    mFile.setFileName(dir + "status");
 
135
    if(!mFile.open(QIODevice::ReadOnly))
 
136
        return false;      /* process has terminated in the meantime */
 
137
 
 
138
    process->uid = 0;
 
139
    process->gid = 0;
 
140
    process->tracerpid = -1;
 
141
    process->numThreads = 0;
 
142
 
 
143
    int size;
 
144
    int found = 0; //count how many fields we found
 
145
    while( (size = mFile.readLine( mBuffer, sizeof(mBuffer))) > 0) {  //-1 indicates an error
 
146
        switch( mBuffer[0]) {
 
147
          case 'N':
 
148
            if((unsigned int)size > sizeof("Name:") && qstrncmp(mBuffer, "Name:", sizeof("Name:")-1) == 0) {
 
149
                if(process->command.isEmpty())
 
150
                process->name = QString::fromLocal8Bit(mBuffer + sizeof("Name:")-1, size-sizeof("Name:")+1).trimmed();
 
151
                if(++found == 5) goto finish;
 
152
            }
 
153
            break;
 
154
          case 'U':
 
155
            if((unsigned int)size > sizeof("Uid:") && qstrncmp(mBuffer, "Uid:", sizeof("Uid:")-1) == 0) {
 
156
            sscanf(mBuffer + sizeof("Uid:") -1, "%Ld %Ld %Ld %Ld", &process->uid, &process->euid, &process->suid, &process->fsuid );
 
157
                if(++found == 5) goto finish;
 
158
            }
 
159
            break;
 
160
          case 'G':
 
161
            if((unsigned int)size > sizeof("Gid:") && qstrncmp(mBuffer, "Gid:", sizeof("Gid:")-1) == 0) {
 
162
            sscanf(mBuffer + sizeof("Gid:")-1, "%Ld %Ld %Ld %Ld", &process->gid, &process->egid, &process->sgid, &process->fsgid );
 
163
                if(++found == 5) goto finish;
 
164
            }
 
165
            break;
 
166
      case 'T':
 
167
        if((unsigned int)size > sizeof("TracerPid:") && qstrncmp(mBuffer, "TracerPid:", sizeof("TracerPid:")-1) == 0) {
 
168
            process->tracerpid = atol(mBuffer + sizeof("TracerPid:")-1);
 
169
            if (process->tracerpid == 0)
 
170
                process->tracerpid = -1;
 
171
            if(++found == 5) goto finish;
 
172
        } else if((unsigned int)size > sizeof("Threads:") && qstrncmp(mBuffer, "Threads:", sizeof("Threads:")-1) == 0) {
 
173
            process->setNumThreads(atol(mBuffer + sizeof("Threads:")-1));
 
174
                if(++found == 5) goto finish;
 
175
            }
 
176
            break;
 
177
          default:
 
178
            break;
 
179
        }
 
180
    }
 
181
 
 
182
    finish:
 
183
    mFile.close();
 
184
    return true;
 
185
}
 
186
 
 
187
long ProcessesLocal::getParentPid(long pid) {
 
188
    Q_ASSERT(pid != 0);
 
189
    d->mFile.setFileName("/proc/" + QString::number(pid) + "/stat");
 
190
    if(!d->mFile.open(QIODevice::ReadOnly))
 
191
        return -1;      /* process has terminated in the meantime */
 
192
 
 
193
    int size; //amount of data read in
 
194
    if( (size = d->mFile.readLine( d->mBuffer, sizeof(d->mBuffer))) <= 0) { //-1 indicates nothing read
 
195
        d->mFile.close();
 
196
        return -1;
 
197
    }
 
198
 
 
199
    d->mFile.close();
 
200
    int current_word = 0;
 
201
    char *word = d->mBuffer;
 
202
 
 
203
    while(true) {
 
204
        if(word[0] == ' ' ) {
 
205
            if(++current_word == 3)
 
206
                break;
 
207
        } else if(word[0] == 0) {
 
208
            return -1; //end of data - serious problem
 
209
        }
 
210
        word++;
 
211
    }
 
212
    long ppid = atol(++word);
 
213
    if (ppid == 0)
 
214
        return -1;
 
215
    return ppid;
 
216
}
 
217
 
 
218
bool ProcessesLocal::Private::readProcStat(const QString &dir, Process *ps)
 
219
{
 
220
    QString filename = dir + "stat";
 
221
    // As an optimization, if the last file read in was stat, then we already have this info in memory
 
222
    if(mFile.fileName() != filename) {
 
223
        mFile.setFileName(filename);
 
224
        if(!mFile.open(QIODevice::ReadOnly))
 
225
            return false;      /* process has terminated in the meantime */
 
226
        if( mFile.readLine( mBuffer, sizeof(mBuffer)) <= 0) { //-1 indicates nothing read
 
227
            mFile.close();
 
228
            return false;
 
229
        }
 
230
        mFile.close();
 
231
    }
 
232
 
 
233
    int current_word = 0;  //count from 0
 
234
    char *word = mBuffer;
 
235
    char status='\0';
 
236
    unsigned long long vmSize = 0;
 
237
    unsigned long long vmRSS = 0;
 
238
    while(current_word < 23) {
 
239
        if(word[0] == ' ' ) {
 
240
            ++current_word;
 
241
            switch(current_word) {
 
242
                case 2: //status
 
243
                    status=word[1];  // Look at the first letter of the status.
 
244
                    // We analyze this after the while loop
 
245
                    break;
 
246
                case 6: //ttyNo
 
247
                    {
 
248
                        int ttyNo = atoi(word+1);
 
249
                        int major = ttyNo >> 8;
 
250
                        int minor = ttyNo & 0xff;
 
251
                        switch(major) {
 
252
                            case 136:
 
253
                                ps->setTty(QByteArray("pts/") + QByteArray::number(minor));
 
254
                                break;
 
255
                            case 5:
 
256
                                ps->setTty(QByteArray("tty"));
 
257
                            case 4:
 
258
                                if(minor < 64)
 
259
                                    ps->setTty(QByteArray("tty") + QByteArray::number(minor));
 
260
                                else
 
261
                                    ps->setTty(QByteArray("ttyS") + QByteArray::number(minor-64));
 
262
                                break;
 
263
                            default:
 
264
                                ps->setTty(QByteArray());
 
265
                        }
 
266
                    }
 
267
                    break;
 
268
                case 13: //userTime
 
269
                    ps->setUserTime(atoll(word+1));
 
270
                    break;
 
271
                case 14: //sysTime
 
272
                    ps->setSysTime(atoll(word+1));
 
273
                    break;
 
274
                case 18: //niceLevel
 
275
                    ps->setNiceLevel(atoi(word+1));  /*Or should we use getPriority instead? */
 
276
                    break;
 
277
                case 22: //vmSize
 
278
                    vmSize = atoll(word+1);
 
279
                    break;
 
280
                case 23: //vmRSS
 
281
                    vmRSS = atoll(word+1);
 
282
                    break;
 
283
                default:
 
284
                    break;
 
285
            }
 
286
        } else if(word[0] == 0) {
 
287
            return false; //end of data - serious problem
 
288
        }
 
289
        word++;
 
290
    }
 
291
 
 
292
    /* There was a "(ps->vmRss+3) * sysconf(_SC_PAGESIZE)" here in the original ksysguard code.  I have no idea why!  After comparing it to
 
293
     *   meminfo and other tools, this means we report the RSS by 12 bytes differently compared to them.  So I'm removing the +3
 
294
     *   to be consistent.  NEXT TIME COMMENT STRANGE THINGS LIKE THAT! :-)
 
295
     *
 
296
     *   Update: I think I now know why - the kernel allocates 3 pages for
 
297
     *   tracking information about each the process. This memory isn't
 
298
     *   included in vmRSS..*/
 
299
    ps->setVmRSS(vmRSS * (sysconf(_SC_PAGESIZE) / 1024)); /*convert to KiB*/
 
300
    ps->setVmSize(vmSize / 1024); /* convert to KiB */
 
301
 
 
302
    switch( status) {
 
303
        case 'R':
 
304
            ps->setStatus(Process::Running);
 
305
            break;
 
306
        case 'S':
 
307
            ps->setStatus(Process::Sleeping);
 
308
            break;
 
309
        case 'D':
 
310
            ps->setStatus(Process::DiskSleep);
 
311
            break;
 
312
        case 'Z':
 
313
            ps->setStatus(Process::Zombie);
 
314
            break;
 
315
        case 'T':
 
316
            ps->setStatus(Process::Stopped);
 
317
            break;
 
318
        case 'W':
 
319
            ps->setStatus(Process::Paging);
 
320
            break;
 
321
        default:
 
322
            ps->setStatus(Process::OtherStatus);
 
323
            break;
 
324
    }
 
325
    return true;
 
326
}
 
327
 
 
328
bool ProcessesLocal::Private::readProcStatm(const QString &dir, Process *process)
 
329
{
 
330
#ifdef _SC_PAGESIZE
 
331
    mFile.setFileName(dir + "statm");
 
332
    if(!mFile.open(QIODevice::ReadOnly))
 
333
        return false;      /* process has terminated in the meantime */
 
334
 
 
335
    if( mFile.readLine( mBuffer, sizeof(mBuffer)) <= 0) { //-1 indicates nothing read
 
336
        mFile.close();
 
337
        return 0;
 
338
    }
 
339
    mFile.close();
 
340
 
 
341
    int current_word = 0;
 
342
    char *word = mBuffer;
 
343
 
 
344
    while(true) {
 
345
            if(word[0] == ' ' ) {
 
346
                    if(++current_word == 2) //number of pages that are shared
 
347
                            break;
 
348
            } else if(word[0] == 0) {
 
349
                return false; //end of data - serious problem
 
350
            }
 
351
            word++;
 
352
    }
 
353
    long shared = atol(word+1);
 
354
 
 
355
    /* we use the rss - shared  to find the amount of memory just this app uses */
 
356
    process->vmURSS = process->vmRSS - (shared * sysconf(_SC_PAGESIZE) / 1024);
 
357
#else
 
358
    process->vmURSS = 0;
 
359
#endif
 
360
    return true;
 
361
}
 
362
 
 
363
 
 
364
bool ProcessesLocal::Private::readProcCmdline(const QString &dir, Process *process)
 
365
{
 
366
    if(!process->command.isNull()) return true; //only parse the cmdline once.  This function takes up 25% of the CPU time :-/
 
367
    mFile.setFileName(dir + "cmdline");
 
368
    if(!mFile.open(QIODevice::ReadOnly))
 
369
        return false;      /* process has terminated in the meantime */
 
370
 
 
371
    QTextStream in(&mFile);
 
372
    process->command = in.readAll();
 
373
 
 
374
    //cmdline separates parameters with the NULL character
 
375
    if(!process->command.isEmpty()) {
 
376
        if(process->command.startsWith(process->name)) {
 
377
            int index = process->command.indexOf(QChar('\0'));
 
378
            process->name = process->command.left(index);
 
379
        }
 
380
        process->command.replace('\0', ' ');
 
381
    }
 
382
 
 
383
    mFile.close();
 
384
    return true;
 
385
}
 
386
 
 
387
bool ProcessesLocal::Private::getNiceness(long pid, Process *process) {
 
388
  int sched = sched_getscheduler(pid);
 
389
  switch(sched) {
 
390
      case (SCHED_OTHER):
 
391
            process->scheduler = KSysGuard::Process::Other;
 
392
            break;
 
393
      case (SCHED_RR):
 
394
            process->scheduler = KSysGuard::Process::RoundRobin;
 
395
            break;
 
396
      case (SCHED_FIFO):
 
397
            process->scheduler = KSysGuard::Process::Fifo;
 
398
            break;
 
399
#ifdef SCHED_IDLE
 
400
      case (SCHED_IDLE):
 
401
            process->scheduler = KSysGuard::Process::SchedulerIdle;
 
402
#endif
 
403
#ifdef SCHED_BATCH
 
404
      case (SCHED_BATCH):
 
405
            process->scheduler = KSysGuard::Process::Batch;
 
406
            break;
 
407
#endif
 
408
      default:
 
409
            process->scheduler = KSysGuard::Process::Other;
 
410
    }
 
411
  if(sched == SCHED_FIFO || sched == SCHED_RR) {
 
412
    struct sched_param param;
 
413
    if(sched_getparam(pid, &param) == 0)
 
414
      process->setNiceLevel(param.sched_priority);
 
415
    else
 
416
      process->setNiceLevel(0);  //Error getting scheduler parameters.
 
417
  }
 
418
 
 
419
#ifdef HAVE_IONICE
 
420
  int ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);  /* Returns from 0 to 7 for the iopriority, and -1 if there's an error */
 
421
  if(ioprio == -1) {
 
422
          process->ioniceLevel = -1;
 
423
          process->ioPriorityClass = KSysGuard::Process::None;
 
424
          return false; /* Error. Just give up. */
 
425
  }
 
426
  process->ioniceLevel = ioprio & 0xff;  /* Bottom few bits are the priority */
 
427
  process->ioPriorityClass = (KSysGuard::Process::IoPriorityClass)(ioprio >> IOPRIO_CLASS_SHIFT); /* Top few bits are the class */
 
428
  return true;
 
429
#else
 
430
  return false;  /* Do nothing, if we do not support this architecture */
 
431
#endif
 
432
}
 
433
 
 
434
bool ProcessesLocal::Private::getIOStatistics(const QString &dir, Process *process)
 
435
{
 
436
    QString filename = dir + "io";
 
437
    // As an optimization, if the last file read in was io, then we already have this info in memory
 
438
    mFile.setFileName(filename);
 
439
    if(!mFile.open(QIODevice::ReadOnly))
 
440
        return false;      /* process has terminated in the meantime */
 
441
    if( mFile.read( mBuffer, sizeof(mBuffer)) <= 0) { //-1 indicates nothing read
 
442
        mFile.close();
 
443
        return false;
 
444
    }
 
445
    mFile.close();
 
446
 
 
447
    int current_word = 0;  //count from 0
 
448
    char *word = mBuffer;
 
449
    while(current_word < 6 && word[0] != 0) {
 
450
        if(word[0] == ' ' ) {
 
451
            qlonglong number = atoll(word+1);
 
452
            switch(current_word++) {
 
453
                case 0: //rchar - characters read
 
454
                    process->setIoCharactersRead(number);
 
455
                    break;
 
456
                case 1: //wchar - characters written
 
457
                    process->setIoCharactersWritten(number);
 
458
                    break;
 
459
                case 2: //syscr - read syscall
 
460
                    process->setIoReadSyscalls(number);
 
461
                    break;
 
462
                case 3: //syscw - write syscall
 
463
                    process->setIoWriteSyscalls(number);
 
464
                    break;
 
465
                case 4: //read_bytes - bytes actually read from I/O
 
466
                    process->setIoCharactersActuallyRead(number);
 
467
                    break;
 
468
                case 5: //write_bytes - bytes actually written to I/O
 
469
                    process->setIoCharactersActuallyWritten(number);
 
470
                default:
 
471
                    break;
 
472
            }
 
473
        }
 
474
        word++;
 
475
    }
 
476
    return true;
 
477
}
 
478
bool ProcessesLocal::updateProcessInfo( long pid, Process *process)
 
479
{
 
480
    bool success = true;
 
481
    QString dir = "/proc/" + QString::number(pid) + '/';
 
482
    if(!d->readProcStat(dir, process)) success = false;
 
483
    if(!d->readProcStatus(dir, process)) success = false;
 
484
    if(!d->readProcStatm(dir, process)) success = false;
 
485
    if(!d->readProcCmdline(dir, process)) success = false;
 
486
    if(!d->getNiceness(pid, process)) success = false;
 
487
    if(mUpdateFlags.testFlag(Processes::IOStatistics) && !d->getIOStatistics(dir, process)) success = false;
 
488
 
 
489
    return success;
 
490
}
 
491
 
 
492
QSet<long> ProcessesLocal::getAllPids( )
 
493
{
 
494
    QSet<long> pids;
 
495
    if(d->mProcDir==NULL) return pids; //There's not much we can do without /proc
 
496
    struct dirent* entry;
 
497
    rewinddir(d->mProcDir);
 
498
    while ( ( entry = readdir( d->mProcDir ) ) )
 
499
        if ( entry->d_name[ 0 ] >= '0' && entry->d_name[ 0 ] <= '9' )
 
500
            pids.insert(atol( entry->d_name ));
 
501
    return pids;
 
502
}
 
503
 
 
504
bool ProcessesLocal::sendSignal(long pid, int sig) {
 
505
    errno = 0;
 
506
    if (pid <= 0) {
 
507
        errorCode = Processes::InvalidPid;
 
508
        return false;
 
509
    }
 
510
    if (kill( (pid_t)pid, sig )) {
 
511
        switch (errno) {
 
512
            case ESRCH:
 
513
                errorCode = Processes::ProcessDoesNotExistOrZombie;
 
514
                break;
 
515
            case EINVAL:
 
516
                errorCode = Processes::InvalidParameter;
 
517
                break;
 
518
            case EPERM:
 
519
                errorCode = Processes::InsufficientPermissions;
 
520
                break;
 
521
            default:
 
522
                break;
 
523
        }
 
524
        //Kill failed
 
525
        return false;
 
526
    }
 
527
    return true;
 
528
}
 
529
 
 
530
bool ProcessesLocal::setNiceness(long pid, int priority) {
 
531
    errno = 0;
 
532
    if (pid <= 0) {
 
533
        errorCode = Processes::InvalidPid;
 
534
        return false;
 
535
    }
 
536
    if (setpriority( PRIO_PROCESS, pid, priority )) {
 
537
        switch (errno) {
 
538
            case ESRCH:
 
539
                errorCode = Processes::ProcessDoesNotExistOrZombie;
 
540
                break;
 
541
            case EINVAL:
 
542
                errorCode = Processes::InvalidParameter;
 
543
                break;
 
544
            case EACCES:
 
545
            case EPERM:
 
546
                errorCode = Processes::InsufficientPermissions;
 
547
                break;
 
548
            default:
 
549
                break;
 
550
        }
 
551
        //set niceness failed
 
552
        return false;
 
553
    }
 
554
    return true;
 
555
}
 
556
 
 
557
bool ProcessesLocal::setScheduler(long pid, int priorityClass, int priority) {
 
558
    errno = 0;
 
559
    if(priorityClass == KSysGuard::Process::Other || priorityClass == KSysGuard::Process::Batch || priorityClass == KSysGuard::Process::SchedulerIdle)
 
560
        priority = 0;
 
561
    if (pid <= 0) {
 
562
        errorCode = Processes::InvalidPid;
 
563
        return false;
 
564
    }
 
565
    struct sched_param params;
 
566
    params.sched_priority = priority;
 
567
    int policy;
 
568
    switch(priorityClass) {
 
569
      case (KSysGuard::Process::Other):
 
570
          policy = SCHED_OTHER;
 
571
          break;
 
572
      case (KSysGuard::Process::RoundRobin):
 
573
          policy = SCHED_RR;
 
574
          break;
 
575
      case (KSysGuard::Process::Fifo):
 
576
          policy = SCHED_FIFO;
 
577
          break;
 
578
#ifdef SCHED_IDLE
 
579
      case (KSysGuard::Process::SchedulerIdle):
 
580
          policy = SCHED_IDLE;
 
581
          break;
 
582
#endif
 
583
#ifdef SCHED_BATCH
 
584
      case (KSysGuard::Process::Batch):
 
585
          policy = SCHED_BATCH;
 
586
          break;
 
587
#endif
 
588
      default:
 
589
          errorCode = Processes::NotSupported;
 
590
          return false;
 
591
    }
 
592
 
 
593
    if (sched_setscheduler( pid, policy, &params) != 0) {
 
594
        switch (errno) {
 
595
            case ESRCH:
 
596
                errorCode = Processes::ProcessDoesNotExistOrZombie;
 
597
                break;
 
598
            case EINVAL:
 
599
                errorCode = Processes::InvalidParameter;
 
600
                break;
 
601
            case EPERM:
 
602
                errorCode = Processes::InsufficientPermissions;
 
603
                break;
 
604
            default:
 
605
                break;
 
606
        }
 
607
        return false;
 
608
    }
 
609
    return true;
 
610
}
 
611
 
 
612
 
 
613
bool ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority) {
 
614
    errno = 0;
 
615
    if (pid <= 0) {
 
616
        errorCode = Processes::InvalidPid;
 
617
        return false;
 
618
    }
 
619
#ifdef HAVE_IONICE
 
620
    if (ioprio_set(IOPRIO_WHO_PROCESS, pid, priority | priorityClass << IOPRIO_CLASS_SHIFT) == -1) {
 
621
        //set io niceness failed
 
622
        switch (errno) {
 
623
            case ESRCH:
 
624
                errorCode = Processes::ProcessDoesNotExistOrZombie;
 
625
                break;
 
626
            case EINVAL:
 
627
                errorCode = Processes::InvalidParameter;
 
628
                break;
 
629
            case EPERM:
 
630
                errorCode = Processes::InsufficientPermissions;
 
631
                break;
 
632
            default:
 
633
                break;
 
634
        }
 
635
        return false;
 
636
    }
 
637
    return true;
 
638
#else
 
639
    errorCode = Processes::NotSupported;
 
640
    return false;
 
641
#endif
 
642
}
 
643
 
 
644
bool ProcessesLocal::supportsIoNiceness() {
 
645
#ifdef HAVE_IONICE
 
646
    return true;
 
647
#else
 
648
    return false;
 
649
#endif
 
650
}
 
651
 
 
652
long long ProcessesLocal::totalPhysicalMemory() {
 
653
    //Try to get the memory via sysconf.  Note the cast to long long to try to avoid a long overflow
 
654
    //Should we use sysconf(_SC_PAGESIZE)  or getpagesize()  ?
 
655
#ifdef _SC_PHYS_PAGES
 
656
    return ((long long)sysconf(_SC_PHYS_PAGES)) * (sysconf(_SC_PAGESIZE)/1024);
 
657
#else
 
658
    //This is backup code in case this is not defined.  It should never fail on a linux system.
 
659
 
 
660
    d->mFile.setFileName("/proc/meminfo");
 
661
    if(!d->mFile.open(QIODevice::ReadOnly))
 
662
        return 0;
 
663
 
 
664
    int size;
 
665
    while( (size = d->mFile.readLine( d->mBuffer, sizeof(d->mBuffer))) > 0) {  //-1 indicates an error
 
666
        switch( d->mBuffer[0]) {
 
667
          case 'M':
 
668
            if((unsigned int)size > sizeof("MemTotal:") && qstrncmp(d->mBuffer, "MemTotal:", sizeof("MemTotal:")-1) == 0) {
 
669
                    d->mFile.close();
 
670
                    return atoll(d->mBuffer + sizeof("MemTotal:")-1);
 
671
            }
 
672
        }
 
673
    }
 
674
    return 0; // Not found.  Probably will never happen
 
675
#endif
 
676
}
 
677
ProcessesLocal::~ProcessesLocal()
 
678
{
 
679
  delete d;
 
680
}
 
681
 
 
682
}