www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - User data of epoll event is reported abnormally by epoll_wait.

reply "blake kim" <netmindms gmail.com> writes:
I am a newbie on D and studying interfacing to C API.

I found abnormal work of epoll_wait.

I stored an arbitrary 64bit number to u64 of epoll_event and 
registered the event with valid fd using epoll_ctl.

When the fd is activated on EPOLLIN, I found u64 value is not 
normal.

epoll has lost the high 4 bytes and just report low 4 bytes.
For example,

import core.sys.linux.epoll;
...
epoll_event event;
event.events = EPOLLIN;
event.u64 = 0x1122334455667788;
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
...
int nfd = epoll_wait(...,&epollevent,...)
...
assert(epollevent.u64==0x1122334455667788); // ==> u64 value is 
55667788

In my investigation, this problem appears by memory align 
mismatch.

In C, sizeof(epoll_event) is 12 but D tells this is 
16.(epoll_event.sizeof)

I wonder why there is this difference between C and D in default 
align.

I got the normal result by modifying epoll_event as follows 
manually.

struct epoll_event {
align(4):
     uint events;
     epoll_data_t data;
}


But I don't think this is right. Many C APIs need structure as 
argument and adjusting align each structure doesn't make sense.

Is this problem a Bug of D ?

I tested this problem on ubuntu 64bit and full example source as 
follows.

-----------------------------------------------------------------------
import std.stdio;
import core.sys.linux.epoll;
import core.sys.posix.unistd;
import std.conv;
import core.thread;

enum  {
     EFD_SEMAPHORE = octal!1,
     EFD_CLOEXEC = octal!2000000,
     EFD_NONBLOCK = octal!4000
}
extern(C) int eventfd(uint initval, int flags);

void testepoll() {
	
	class MyThr: Thread {
		int msgfd;
		this() {
			super(&thread_proc);
			
		}
		
		void thread_proc() {
			int efd = epoll_create(10);
			int fd = eventfd(0, EFD_NONBLOCK);
			msgfd =fd;
			
			epoll_event event;
			event.events = EPOLLIN;
			event.data.u64 = 0x1122334455667788;
			epoll_ctl(efd, EPOLL_CTL_ADD, fd, &event);
			
			ulong val=1;
			core.sys.posix.unistd.write(msgfd, &val, 8);
			
			int nfd;
			epoll_event pollevent;
			for(;;) {
				nfd = epoll_wait(efd, &pollevent, 1, -1);
				if(nfd>0) {
					ulong d = pollevent.data.u64;
					writefln("user, %0x", d); // -> print out is 55667788, high 
4 bytes(0x11223344) is lost !!!
					break;
					
				}
			}
			
		}
	}
	
	auto thr = new MyThr();
	thr.start();
	thr.join();
}

void main() {
	testepoll();
}
---------------------------------------------------------------------------------
Aug 19 2014
next sibling parent reply "Dominikus Dittes Scherkl" writes:
On Wednesday, 20 August 2014 at 06:11:42 UTC, blake kim wrote:
 But I don't think this is right. Many C APIs need structure as 
 argument and adjusting align each structure doesn't make sense.

 Is this problem a Bug of D ?
Default alignment in D is pointersize (size_t) - so 8 on 64bit. But most C compilers default to 4 regardless of pointersize. I think this is more a bug in C than in D.
Aug 19 2014
parent reply "blake kim" <netmindms gmail.com> writes:
On Wednesday, 20 August 2014 at 06:17:43 UTC, Dominikus Dittes 
Scherkl wrote:
 On Wednesday, 20 August 2014 at 06:11:42 UTC, blake kim wrote:
 But I don't think this is right. Many C APIs need structure as 
 argument and adjusting align each structure doesn't make sense.

 Is this problem a Bug of D ?
Default alignment in D is pointersize (size_t) - so 8 on 64bit. But most C compilers default to 4 regardless of pointersize. I think this is more a bug in C than in D.
epoll_wait is a system API on Linux. So, I can't agree that it is a bug of C in alignment. C uses 4 byte alignment, then, I think, it is sensible that D should follow that. Actually, In core.sys.linux.epoll.d, struct epoll_event doesn't assign a specific align so that the problem is caused.
Aug 20 2014
parent reply "blake kim" <netmindms gmail.com> writes:
On Wednesday, 20 August 2014 at 07:02:52 UTC, blake kim wrote:
 On Wednesday, 20 August 2014 at 06:17:43 UTC, Dominikus Dittes 
 Scherkl wrote:
 On Wednesday, 20 August 2014 at 06:11:42 UTC, blake kim wrote:
 But I don't think this is right. Many C APIs need structure 
 as argument and adjusting align each structure doesn't make 
 sense.

 Is this problem a Bug of D ?
Default alignment in D is pointersize (size_t) - so 8 on 64bit. But most C compilers default to 4 regardless of pointersize. I think this is more a bug in C than in D.
epoll_wait is a system API on Linux. So, I can't agree that it is a bug of C in alignment. C uses 4 byte alignment, then, I think, it is sensible that D should follow that. Actually, In core.sys.linux.epoll.d, struct epoll_event doesn't assign a specific align so that the problem is caused.
I found the solution. This is a obvious bug of core.sys.linux.epoll.d. The default alignment of all of both C and D is 8 on 64bit OS. But epoll_event is packed as follows.(/usr/include/x86_64-linux-gnu/sys/epoll.h) struct epoll_event { uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ } __attribute__ ((__packed__)); Therefore, epoll_event should be declared in D as follows. extern(C) align(1) struct epoll_event { align(1): uint events; epoll_data_t data; }
Aug 20 2014
next sibling parent ketmar via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Wed, 20 Aug 2014 10:01:05 +0000
blake kim via Digitalmars-d <digitalmars-d puremagic.com> wrote:

fill bugreport, please. and submit PR if you can.
Aug 20 2014
prev sibling parent Etienne <etcimon gmail.com> writes:
On 2014-08-20 6:01 AM, blake kim wrote:
 extern(C) align(1) struct epoll_event {
 align(1):
    uint events;
    epoll_data_t data;
 }
Wow, that fixes my issue! I couldn't use more than 1 event in my array because of misalignment, thanks!
Aug 21 2014
prev sibling parent "Daniel Murphy" <yebbliesnospam gmail.com> writes:
"blake kim"  wrote in message news:slmejjrekoahgbmtitpo forum.dlang.org...

 In my investigation, this problem appears by memory align mismatch.

 In C, sizeof(epoll_event) is 12 but D tells this is 
 16.(epoll_event.sizeof)
With default alignment, the D layout must match the C layout. I've fun a fuzz-tester on this on linux64, so you can be reasonable confident DMD will behave correctly for structs containing basic types.
Aug 20 2014