harry’s memorandum

おれおれメモ

プロセスの優先度を強制的に変更

仕事で少し必要になったので得意じゃないVCを。

OpenProcess()でプロセスのハンドラを取得してSetPriorityClass()で優先度を変更するだけと思っていたのですが、一部のプロセスはアクセス拒否で弾かれてしまいました。サービスプロセスやSYSTEMユーザで起動しているプロセスは変更できないのですね。

でもSysinternal社のProcess Explorer*1だとお構いなしに優先度を変更できるので少し調べたところ、こんな感じでいけるのではなかろうかと。(あってるのか?)

  1. AdjustTokenPrivileges()で特権をつけて
  2. OpenProcess()でハンドラを取得して
  3. SetPriorityClass()で優先度変更
  4. AdjustTokenPrivileges()の特権を無効

とりあえずゴミコード。ここのMicrosoftサポートオンラインをまるパクリ。

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

#define RTN_OK 0
#define RTN_USAGE 1
#define RTN_ERROR 13

BOOL SetPrivilege(
  HANDLE hToken,          // token handle
  LPCTSTR Privilege,      // Privilege to enable/disable
  BOOL bEnablePrivilege   // TRUE to enable.  FALSE to disable
);
void DisplayError(LPTSTR szAPI);

int _tmain(int argc, char **argv)
{
  DWORD priority_class = BELOW_NORMAL_PRIORITY_CLASS;
  DWORD pid;
  DWORD result = true;
  HANDLE hProcess;
  HANDLE hToken;

  if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken))
  {
    if (GetLastError() == ERROR_NO_TOKEN)
    {
      if (!ImpersonateSelf(SecurityImpersonation))
        return RTN_ERROR;

      if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)){
        DisplayError("OpenThreadToken");
        return RTN_ERROR;
      }
  } else
    return RTN_ERROR;
  }

  // enable SeDebugPrivilege
  if(!SetPrivilege(hToken, SE_DEBUG_NAME, TRUE))
  {
    DisplayError("SetPrivilege");
    CloseHandle(hToken);
    return RTN_ERROR;
  }

  pid = atoi(argv[1]);
  if ((hProcess = OpenProcess (PROCESS_SET_INFORMATION, FALSE, pid)) == NULL)
  {
    DisplayError("OpenProcess");
    CloseHandle(hToken);
    return false;
  }

  if (!SetPriorityClass(hProcess, priority_class))
  {
    DisplayError("SetPriorityClass");
    result = false;
  }
  else
  {
    fprintf(stdout,"SetPriorityClass() Success: %d\n", priority_class);
  }
  
  // disable SeDebugPrivilege
  SetPrivilege(hToken, SE_DEBUG_NAME, FALSE);

  CloseHandle (hProcess);
  CloseHandle (hToken);

  return true;
}

BOOL SetPrivilege( 
  HANDLE hToken,  // token handle 
  LPCTSTR Privilege,  // Privilege to enable/disable 
  BOOL bEnablePrivilege  // TRUE to enable. FALSE to disable 
) 
{ 
  TOKEN_PRIVILEGES tp = { 0 }; 
  // Initialize everything to zero 
  LUID luid; 
  DWORD cb=sizeof(TOKEN_PRIVILEGES); 
  if(!LookupPrivilegeValue( NULL, Privilege, &luid ))
    return FALSE; 
  tp.PrivilegeCount = 1; 
  tp.Privileges[0].Luid = luid; 
  if(bEnablePrivilege) { 
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
  } else { 
    tp.Privileges[0].Attributes = 0; 
  } 
  AdjustTokenPrivileges( hToken, FALSE, &tp, cb, NULL, NULL ); 
  if (GetLastError() != ERROR_SUCCESS) 
    return FALSE; 

  return TRUE;
}

void DisplayError(
  LPTSTR szAPI    // pointer to failed API name
)
{
  LPTSTR MessageBuffer;
  DWORD dwBufferLength;

  fprintf(stderr,"%s() error!\n", szAPI);

  if(dwBufferLength=FormatMessage(
    FORMAT_MESSAGE_ALLOCATE_BUFFER |
    FORMAT_MESSAGE_FROM_SYSTEM,
    NULL,
    GetLastError(),
    GetSystemDefaultLangID(),
    (LPTSTR) &MessageBuffer,
    0,
    NULL
    ))
  {
    DWORD dwBytesWritten;

    // Output message string on stderr
    WriteFile(GetStdHandle(STD_ERROR_HANDLE), MessageBuffer, dwBufferLength, &dwBytesWritten, NULL);

    // free the buffer allocated by the system
    LocalFree(MessageBuffer);
  }
}

いちおう出来てるっぽいかな。

プロセスの優先順位クラスを備忘録としてメモ。

REALTIME_PRIORITY_CLASS リアルタイム(R)
HIGH_PRIORITY_CLASS 高(H)
ABOVE_NORMAL_PRIORITY_CLASS 通常以上(A)
NORMAL_PRIORITY_CLASS 通常(N)
BELOW_NORMAL_PRIORITY_CLASS 通常以下(B)
IDLE_PRIORITY_CLASS 低(L)

詳細はMSDNこのあたりで。

*1:sysinternalのツールさいこー

freeSSHdを試してみた

freeSSHd という Free の Windows版 SSHサーバがあるので使ってみました。

インストール

インストーラを何も考えずにすべてYesとOkを押して終わり。

設定

タスクトレイのアイコンから [setting] -> [Users] の Add を押します。Windowsの既存の認証にする場合は NT Authentication を選択してユーザを入力します。使いたい機能にチェックを入れます。わからない場合は Shell, SFTP, Tunnelingすべてにチェックしてください。
f:id:dharry:20090222222125j:image
Cygwinをインストールしている場合は、Cygtermに変更すると便利になります。
f:id:dharry:20090222222124j:image
ファイアウォールにポート22の許可を入れましょう。
f:id:dharry:20090222222424j:image

Windows7beta版を試してみた

巷ではWindows7は結構軽くて速いと言われているので、VMware-Server1.xにインストールして確認してみました。

インストール画面

ほとんどWindows 2008 Server と同じ。
f:id:dharry:20090127024201j:image
カーネルバージョンはNT6.1。
f:id:dharry:20090127024157j:image

簡易ベンチ

色々なところでベンチマークが行われていますね。リソース使用量だけ知りたかったので、スタートメニューにテストコードを登録しておいて、起動直後の「メモリ使用量とサービスの数」を確認しました。

VMwareホストマシン
OS Microsoft Windows XP Professional SP3
CPU AMD Phenom X4 9550 Quad Core
VMwareゲストマシン
比較OS WindowsXPXP3, Windows7beta版
CPU 2CPU割り当て
Memory 1024MB
Disk 30GB(スパースファイルで作成)
VMwareTools インストール済み
  • テストコード
Set wbemServices = GetObject("winmgmts:\\" & "localhost")

Set wbemObjectSet = wbemServices.InstancesOf("Win32_OperatingSystem")
For Each wbemObject In wbemObjectSet
  WScript.Echo "TotalMemory = " & wbemObject.TotalVisibleMemorySize
  WScript.Echo "UsedMemory = " & wbemObject.TotalVisibleMemorySize - wbemObject.FreePhysicalMemory
  WScript.Echo "FreeMemory = " & wbemObject.FreePhysicalMemory
Next

Set wbemObjectSet = wbemServices.InstancesOf("Win32_Service")
For Each wbemObject In wbemObjectSet
  if wbemObject.State = "Running" then
    count = count + 1
  end if
Next
WScript.Echo "Service Count: " & count
VMwareゲスト メモリ使用量 サービス数
WindowsXPSP3 Total:1048048 / Used:204104 43
Windows7beta Total:1047372 / Used:313536 43

結果Windows7beta版の方が、100MBほど使用量が多い結果になりました。無駄なデスクトップの視覚効果や自動起動するアプリケーションを削ればもう少し肉薄できる感じがします。サービスの数もあまり変わらないようです。Windowsはバージョンが上がるたびに知らないサービスが増えてて困ったものですが今回はそれほど違いはなさそうですね。

しかし、WMIで取得したTotalのメモリサイズの値がWindowsXPとWindows7で微妙に違うのが気になるところです。*1

*1:WMIに大幅な変更があったら嫌だな