2017/11/08

Recent entries from same category

  1. Golang の archive/zip でタイムゾーンの問題とファイル名の問題が解決した。
  2. net/http でレスポンスの内容を確認したいなら io.TeeReader を使おう
  3. Golang で物理ファイルの操作に path/filepath でなく path を使うと爆発します。
  4. gRPC のサービスが簡単に作れるライブラリ「lile」
  5. CreateFile で FILE_SHARE_DELETE を指定するとどうなるか

追記

CreationFlags に直接指定出来ますね...

package main

import (
    "log"
    "os/exec"
    "syscall"
)

const (
    _IDLE_PRIORITY_CLASS = 0x40
)

func main() {
    cmd := exec.Command("notepad")
    cmd.SysProcAttr = &syscall.SysProcAttr{
        CreationFlags: syscall.CREATE_UNICODE_ENVIRONMENT | _IDLE_PRIORITY_CLASS,
    }
    err := cmd.Start()
    if err != nil {
        log.Fatal(err)
    }
    cmd.Wait()
}

追記ここまで

先日 GoCon に参加した際、牛乳を吹いてるアイコンの人に「Golang で優先度を変えてプロセスを起動するにはどうしたらいいんでしょうね」というお題を貰ったので書いてみました。

syscall には必要な API しか持ってないので API を持ってくるところが若干めんどくさいですが、出来る事は出来ます。プロセスをサスペンド状態で起動しておき、優先度を変更後にリジュームします。(起動後いきなり激しい動きをするヤバい奴がいない事もない)

package main

import (
    "log"
    "os/exec"
    "syscall"
    "unsafe"
)

const (
    _CREATE_SUSPENDED        = 0x00000004
    _IDLE_PRIORITY_CLASS     = 0x40
    _PROCESS_SET_INFORMATION = 0x0200
)

var (
    kernel32             = syscall.NewLazyDLL("kernel32")
    procSetPriorityClass = kernel32.NewProc("SetPriorityClass")
    procOpenThread       = kernel32.NewProc("OpenThread")
    procResumeThread     = kernel32.NewProc("ResumeThread")
    procThread32First    = kernel32.NewProc("Thread32First")
    procThread32Next     = kernel32.NewProc("Thread32Next")
)

func resumeChildThread(childpid interror {
    snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPTHREAD, 0)
    if err != nil {
        return err
    }
    defer syscall.CloseHandle(snapshot)

    const _THREAD_SUSPEND_RESUME = 0x0002

    type ThreadEntry32 struct {
        Size           uint32
        tUsage         uint32
        ThreadID       uint32
        OwnerProcessID uint32
        BasePri        int32
        DeltaPri       int32
        Flags          uint32
    }

    var te ThreadEntry32
    te.Size = uint32(unsafe.Sizeof(te))
    ret, _, err := procThread32First.Call(uintptr(snapshot), uintptr(unsafe.Pointer(&te)))
    if ret == 0 {
        return err
    }
    for te.OwnerProcessID != uint32(childpid) {
        ret, _, err = procThread32Next.Call(uintptr(snapshot), uintptr(unsafe.Pointer(&te)))
        if ret == 0 {
            return err
        }
    }
    h, _, err := procOpenThread.Call(_THREAD_SUSPEND_RESUME, 1uintptr(te.ThreadID))
    if h == 0 {
        return err
    }
    defer syscall.Close(syscall.Handle(h))

    ret, _, err = procResumeThread.Call(h)
    if ret == 0xffffffff {
        return err
    }
    return nil
}

func main() {
    cmd := exec.Command("notepad")
    cmd.SysProcAttr = &syscall.SysProcAttr{
        CreationFlags: syscall.CREATE_UNICODE_ENVIRONMENT | _CREATE_SUSPENDED,
    }
    err := cmd.Start()
    if err != nil {
        log.Fatal(err)
    }

    hProcess, err := syscall.OpenProcess(_PROCESS_SET_INFORMATION, trueuint32(cmd.Process.Pid))
    if err != nil {
        log.Fatal(err)
    }
    r1, _, err := procSetPriorityClass.Call(uintptr(hProcess), uintptr(_IDLE_PRIORITY_CLASS))
    if r1 == 0 {
        log.Fatal(err)
    }
    syscall.CloseHandle(hProcess)

    resumeChildThread(cmd.Process.Pid)
    cmd.Wait()
}

blog comments powered by Disqus