uintptr转int的问题

442 views
Skip to first unread message

shada

unread,
Mar 3, 2012, 8:58:13 AM3/3/12
to golang-china
f, e := os.OpenFile("/dev/null", os.O_RDWR, 0)
if e == nil {
	fd := f.Fd()
	syscall.Dup2(fd, os.Stdin.Fd())
}

cannot use os.Stdin.Fd() (type uintptr) as type int in function argument

以上代码是release版的,我现在用的是weekly.2-22,请问该如何转换?

平民四月份

unread,
Mar 3, 2012, 9:04:27 AM3/3/12
to golang...@googlegroups.com
package main

import "fmt"

func main() {
        var i uintptr = 1
        var j int
        j = int(i) 
fmt.Println("Hello, 世界", j)
}


经测试 2.14号版本以及 r60.3,可以直接转,2.22号,没有运行环境,故而未测试

2012/3/3 shada <laf...@gmail.com>

--
来自: Golang-China ~ 中文Go语言技术邮件列表
详情: http://groups.google.com/group/golang-china
官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina



--
 Face the sea, for the spring flowers blossoming




minux

unread,
Mar 3, 2012, 9:16:50 AM3/3/12
to golang...@googlegroups.com


2012/3/3 shada <laf...@gmail.com>

f, e := os.OpenFile("/dev/null", os.O_RDWR, 0)
if e == nil {
	fd := f.Fd()
	syscall.Dup2(fd, os.Stdin.Fd())
}
syscall.Dup2(int(fd), int(os.Stdin.Fd()))

os.(*File).Fd()返回uintptr是为了兼容Windows。
本来我是想把syscall的所有fd也全改成uintptr类型的,但是晚了一步,
加上Rob Pike觉得不应该鼓励大家用syscall,所以没让改。

平民四月份

unread,
Mar 3, 2012, 9:24:50 AM3/3/12
to golang...@googlegroups.com
minux 给个从uintptr->int 的转化方案吧,2.14都可以直接转的

2012/3/3 minux <minu...@gmail.com>

--
来自: Golang-China ~ 中文Go语言技术邮件列表
详情: http://groups.google.com/group/golang-china
官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina

minux

unread,
Mar 3, 2012, 9:33:44 AM3/3/12
to golang...@googlegroups.com

2012/3/3 平民四月份 <lew...@gmail.com>

minux 给个从uintptr->int 的转化方案吧,2.14都可以直接转的
目前只能在调用syscall的相关函数之前自己强制转换了,int(fd)即可。
要是早点提这个就好了,等提的时候Go 1 API已经frozen了。于是整个Go 1.x系列都只能
忍受这个了。

但是根据Rob Pike的态度来看,我觉得Go 2.x也不会改这个的。

平民四月份

unread,
Mar 3, 2012, 9:48:15 AM3/3/12
to golang...@googlegroups.com
其实你没弄明白,楼主发这贴的目的,他的意思是,int(fd),在2.22号这个版本,是不能通过编译的,我试过r60.3, 2.22-weekly都是可以直接cast的

2012/3/3 minux <minu...@gmail.com>

--
来自: Golang-China ~ 中文Go语言技术邮件列表
详情: http://groups.google.com/group/golang-china
官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina

minux

unread,
Mar 3, 2012, 10:55:48 AM3/3/12
to golang...@googlegroups.com


2012/3/3 平民四月份 <lew...@gmail.com>

其实你没弄明白,楼主发这贴的目的,他的意思是,int(fd),在2.22号这个版本,是不能通过编译的,我试过r60.3, 2.22-weekly都是可以直接cast的
那就诡异了。我又实验了一下weekly.2012-02-22版本,直接int(fd)是不会有问题的。我也没听说过类似的bug
报告。
还得等楼主贴出更多的代码并且说明具体的版本,注意由于最近cmd/dist的bug,如果是自己编译的,不管你
hg update到哪个用cmd/dist的weekly版本编译出来的go version都会是weekly.2012-02-22,但是后面的hg版
本号是对的。

我的测试用例:
package main
import ("fmt"; "os")
func main() {
    fd := os.Stdin.Fd()
    fmt.Printf("%T\n", fd)
    fmt.Printf("%d\n", int(fd))
}
输出结果是:
uintptr
0

shada

unread,
Mar 4, 2012, 8:16:56 AM3/4/12
to golang...@googlegroups.com
2-22可以强制转换,是我搞错了,不好意思。
func daemon(nochdir, noclose int) int {
var ret uintptr
var err syscall.Errno

ret, _, err = syscall.Syscall(syscall.SYS_FORK, 0, 0, 0)
if err != 0 {
return -1
}
switch ret {
case 0:
break
default:
os.Exit(0)
}

pid,r:=syscall.Setsid()
if pid==-1 || r!=nil{
return -1
}
if nochdir == 0 {
os.Chdir("/")
}

if noclose == 0 {


f, e := os.OpenFile("/dev/null", os.O_RDWR, 0)
if e == nil {
fd := f.Fd()

syscall.Dup2(int(fd), int(os.Stdin.Fd()))
}
f, e = os.OpenFile("/var/log/shadaproxy-client", os.O_RDWR, 0)


if e == nil {
fd := f.Fd()

syscall.Dup2(int(fd), int(os.Stdout.Fd()))
syscall.Dup2(int(fd), int(os.Stderr.Fd()))
}
}

return 0
}

现在可以正常编译通过了,守护功能正常,但标准输出和错误输出重定向功能不行,到/var/log下看没有那个文件,noclose传的是0。

minux

unread,
Mar 4, 2012, 9:48:57 AM3/4/12
to golang...@googlegroups.com

2012/3/4 shada <laf...@gmail.com>

2-22可以强制转换,是我搞错了,不好意思。
func daemon(nochdir, noclose int) int {
       var ret uintptr
       var err syscall.Errno

       ret, _, err = syscall.Syscall(syscall.SYS_FORK, 0, 0, 0)
       if err != 0 {
               return -1
       }
建议:函数类型改成返回error,然后这里返回err。以下类似。这样比较符合一般的
Go编码风格。 
       switch ret {
       case 0:
               break
       default:
               os.Exit(0)
       }

       pid,r:=syscall.Setsid()
       if pid==-1 || r!=nil{
               return -1
       }
       if nochdir == 0 {
               os.Chdir("/")
       }

       if noclose == 0 {
               f, e := os.OpenFile("/dev/null", os.O_RDWR, 0)
这里"/dev/null"可以换成os.DevNull,这样移植性稍微好点。当然,既然已经用了syscall,那么就
意味着这个代码只能跑在Unix上了,所以原来的用法也没问题。我只是提示下os底下有一个可移植
的const可以用。 
               if e == nil {
                       fd := f.Fd()
                       syscall.Dup2(int(fd), int(os.Stdin.Fd()))
               }
我想知道为啥你先dup2一个/dev/null过去?然后再dup一个log文件呢?我觉得顺序反了,
应该是在log文件打开失败或者dup2不成功地时候再dup /dev/null。 
               f, e = os.OpenFile("/var/log/shadaproxy-client", os.O_RDWR, 0)
你忘记加os.O_CREATE, 另外,最后一个参数是0也不太应该,不然如果文件不存在创建的文件的
属性也就是0了,这个不太符合常理。 还有,作为log文件来说,这里似乎还应该加上O_APPEND,
而且只要写就够了吧?
我考虑os.OpenFile的文档里应该提一下O_CREATE。
               if e == nil {
                       fd := f.Fd()
                       syscall.Dup2(int(fd), int(os.Stdout.Fd()))
                       syscall.Dup2(int(fd), int(os.Stderr.Fd()))
               }
其实犯这个错误的更主要的原因是这段代码不是Idiomatic Go,Go一般是这样判断的:
if e != nil {
   // report error or just panic in case you don't expect any errors (very unlikely)
}
养成习惯处理错误,这类问题就能早发现。
顺便说一句,我个人不建议随随便便用panic处理错误情况。
       }

       return 0
}

Ruiqi Hong

unread,
Mar 4, 2012, 9:55:05 AM3/4/12
to golang...@googlegroups.com
dup2 before fork?

minux

unread,
Mar 4, 2012, 10:14:13 AM3/4/12
to golang...@googlegroups.com

2012/3/4 Ruiqi Hong <hong...@gmail.com>
dup2 before fork?
我觉得不合适,如果fork失败,parent进程没准还需要stderr来报错呢。

Ruiqi Hong

unread,
Mar 4, 2012, 10:33:58 PM3/4/12
to golang...@googlegroups.com
把Syscall改成RawSyscall就正常了,但不知道为什么?好像和调度器有关系...

--

minux

unread,
Mar 4, 2012, 10:44:15 PM3/4/12
to golang...@googlegroups.com

2012/3/5 Ruiqi Hong <hong...@gmail.com>
把Syscall改成RawSyscall就正常了,但不知道为什么?好像和调度器有关系...
恩 如果是这样的话,就是跟Go的调度器有关系了。
Syscall和RawSyscall的唯一区别就是是否调用runtime.entersyscall/runtime.exitsyscall。

目前的Go调度器设计是一旦一个goroutine进入了系统调用,如果当前还有别的goroutine
可以继续运行(注意Go后台有别的goroutine的,比如gc用的之类),那么就会创建一个新的
OS thread。

而fork的时候绝对不能让调度器创建别的OS thread,之所以Go没有提供Deamonize()这样
的标准库函数就是因为线程和fork之间有比较复杂的交互。

如果要daemonize的话,最佳时机是main.init()里面。只要Go runtime创建了新的OS thread,
fork之后的Go程序基本上100%不会工作正常(或者说你很难让他工作正常,不是不可能)。

Uhioins Dell

unread,
Mar 5, 2012, 4:30:58 AM3/5/12
to golang...@googlegroups.com
uinptr 是什么类型? 是无符号整型指针吗?不好意思,小白一个,请各位前辈不吝赐教。
另外能否给一个GO LANG学习路线图呢!!!?现在完了中文版的<学习GO语言>,正在看  官方《A tour of go》

Jay True

unread,
Mar 5, 2012, 4:39:42 AM3/5/12
to golang...@googlegroups.com
uintptr 表示一个与指针类型等长的无符号整型。

shada

unread,
Mar 5, 2012, 7:31:28 AM3/5/12
to golang...@googlegroups.com
已经修改,功能正常了:
func daemon(nochdir, noclose int) error {

    var ret uintptr
    var err syscall.Errno

    ret, _, err = syscall.Syscall(syscall.SYS_FORK, 0, 0, 0)
    if err != 0 {
        return error(err)

    }
    switch ret {
    case 0:
        break
    default:
        os.Exit(0)
    }

    pid,r:=syscall.Setsid()
    if pid==-1 || r!=nil{
        return r

    }
    if nochdir == 0 {
        os.Chdir("/")
    }

    if noclose == 0 {
        f, e := os.OpenFile(os.DevNull, os.O_RDWR, 0)
        if e != nil {
            panic(e)

        }
        fd := f.Fd()
        syscall.Dup2(int(fd), int(os.Stdin.Fd()))

        f2, e := os.OpenFile("/var/log/shadaproxy-client", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
        if e != nil {
            panic(e)
        }
        fd2 := f2.Fd()
        syscall.Dup2(int(fd2), int(os.Stdout.Fd()))
        syscall.Dup2(int(fd2), int(os.Stderr.Fd()))
    }

    return nil
}

感谢minux

Ruiqi Hong

unread,
Mar 5, 2012, 7:46:33 AM3/5/12
to golang...@googlegroups.com
我这功能不正常呢?版本:go version weekly.2012-03-04 +a42f9321c5e3

shada

unread,
Mar 5, 2012, 8:01:28 AM3/5/12
to golang...@googlegroups.com
$ go version
go version weekly.2012-03-04 +f4470a54e6db

刚升级到了3-4测试,可以正常编译通过啊。

Ruiqi Hong

unread,
Mar 5, 2012, 9:23:30 AM3/5/12
to golang...@googlegroups.com
可以编译通过,但是标准输出不会重定向,且fork出的进程不会退出

minux

unread,
Mar 5, 2012, 10:20:28 AM3/5/12
to golang...@googlegroups.com


2012/3/5 Ruiqi Hong <hong...@gmail.com>
可以编译通过,但是标准输出不会重定向,且fork出的进程不会退出
strace -f ./prog
看看到底哪里出错了。 

Ruiqi Hong

unread,
Mar 5, 2012, 10:58:28 PM3/5/12
to golang...@googlegroups.com
trace.txt

shada

unread,
Mar 6, 2012, 8:25:25 AM3/6/12
to golang...@googlegroups.com
不是以root权限运行的?
我的会写日志呢。

shada

unread,
Mar 6, 2012, 8:26:04 AM3/6/12
to golang...@googlegroups.com
并且多余的进程正常退出了。

在 2012年3月6日 下午9:25,shada <laf...@gmail.com>写道:
不是以root权限运行的?
我的会写日志呢。

Ruiqi Hong

unread,
Mar 6, 2012, 8:51:28 PM3/6/12
to golang...@googlegroups.com
可能是由于其它goroutine的影响

这个是最简单的调用daemon的程序,你那试试看
test.7z

Ruiqi Hong

unread,
Mar 6, 2012, 10:07:08 PM3/6/12
to golang...@googlegroups.com
import _ "net" 后正常
试了只导入”net导入的包“,而不导入net本身,失败
net执行了什么初始化操作么?

在 2012年3月7日 上午9:51,Ruiqi Hong <hong...@gmail.com>写道:
可能是由于其它goroutine的影响

这个是最简单的调用daemon的程序,你那试试看

shada

unread,
Mar 7, 2012, 12:38:40 AM3/7/12
to golang...@googlegroups.com
我的工程是main所在的文件没有导入net,在其它文件中有导入net,main中daemon之前没有网络操作。

Ruiqi Hong

unread,
Mar 7, 2012, 2:07:31 AM3/7/12
to golang...@googlegroups.com
嗯,我也不知道为什么,只要程序里导入了net(间接也行,比如导入net/http),就可以了,不用运行里面的东西。
但是在net里也没找到和初始化有关的东西..
Reply all
Reply to author
Forward
0 new messages