File: alinuxaio.c

package info (click to toggle)
libmems 1.6.0%2B4725-9
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 2,120 kB
  • sloc: cpp: 21,579; ansic: 4,312; xml: 115; makefile: 103; sh: 26
file content (283 lines) | stat: -rw-r--r-- 8,032 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "libMems/dmSML/alinuxaio.h"
#ifdef USE_LINUX_AIO

#include <libaio.h>

#include "libMems/dmSML/asyncio.h"
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
/*
#define __NR_io_setup		245
#define __NR_io_destroy		246
#define __NR_io_getevents	247
#define __NR_io_submit		248
#define __NR_io_cancel		249
*/

io_context_t ctx_id = NULL;

#ifndef __u64
typedef unsigned long long __u64;
#endif

__u64 current_id = 0;

unsigned event_max = 10000;

// error = sys_io_destroy( ctx_id );


typedef struct completion_id_s {
	__u64 data;
	struct completion_id_s* next;
	struct completion_id_s* last;
} completion_id_t;

typedef struct completion_id_list_s { 
    int nitems;
    completion_id_t * head;
} completion_id_list_t;

// buffer list manipulations
// returns argument
completion_id_list_t * InitListComp( completion_id_list_t * list );
void PushHeadComp( completion_id_list_t * list, completion_id_t * item );
void PushTailComp( completion_id_list_t * list, completion_id_t * item );
completion_id_t * PopHeadComp( completion_id_list_t * list );
completion_id_t * PopTailComp( completion_id_list_t * list );
// returns second argument
completion_id_t * RemoveItemComp( completion_id_list_t * list, completion_id_t * item );


// buffer list manipulations
// returns argument
completion_id_list_t * InitListComp( completion_id_list_t * list ) {
    list->head = NULL;
    list->nitems = 0;
    return( list );
}


void PushHeadComp( completion_id_list_t * list, completion_id_t * item ) {
    // one special case for empty list, because we can't
    // dereference list->head until we assign to it.
    if( list->head == NULL ) {
        list->head = item;
        list->nitems = 1;
        list->head->next = list->head;
        list->head->last = list->head;
        return;
    }
    // other cases are easier, because no more null pointers.
    item->last = list->head->last;
    item->next = list->head;
    list->head->last->next = item;
    list->head->last = item;
    list->head = item;
    // we added an item.
    list->nitems++;
}

void PushTailComp( completion_id_list_t * list, completion_id_t * item ) {
    // this is exactly equivalent to doing a PushHead and
    // then backing up the list head one.
    // get the item in there
    PushHeadComp( list, item );
    // back up the head.
    list->head = list->head->last;
}

completion_id_t * PopHeadComp( completion_id_list_t * list ) {
    completion_id_t *ret;
    // just get rid of the head item and return it.
    if( list->head == NULL ) {
        return( NULL );
    }
    list->head->next->last = list->head->last;
    list->head->last->next = list->head->next;
    ret = list->head;
    list->head = list->head->next;
    ret->next = ret->last = NULL;
    list->nitems--;
    if( list->nitems == 0 ) {
        list->head = NULL;
    }
    return( ret );
}

completion_id_t * PopTailComp( completion_id_list_t * list ) {
    // just get rid of the tail item and return it.
    if( list->head == NULL ) {
        return( list->head );
    }
    // otherwise, a pop tail is equivalent to moving the
    // head back one and popping head.
    list->head = list->head->last;
    return( PopHeadComp( list ) );
}

// returns second argument
completion_id_t * RemoveItemComp( completion_id_list_t * list, completion_id_t * item ) {
    // FIXME: handle NULL cases in a reasonable way?
    if( item == list->head ) {
        return( PopHeadComp( list ) );
    }
    item->next->last = item->last;
    item->last->next = item->next;
    item->next = item->last = NULL;
    list->nitems--;
    if( list->nitems == 0 ) {
        list->head = NULL;
    }
    return( item );
}


completion_id_list_t *completion_list = NULL;

int OpenLinux( aFILE * file, const char *path, int mode ){
	long error;
	if( ctx_id == 0 ){
		error = io_queue_init( event_max, &ctx_id );
		if( error != 0 )
			perror( "io_setup" );
	}
	if( completion_list == NULL ){
		completion_list = (completion_id_list_t*)malloc( sizeof( completion_id_list_t ) );
		completion_list = InitListComp( completion_list );
	}
		
	if(mode == A_READ){
		file->file_descriptor = open(path, O_LARGEFILE | O_RDONLY, S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP );
	}else{
		file->file_descriptor = open(path, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE,  S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP);
	}
	if(file->file_descriptor < 0){
		
		perror(path);
	}
	return file->file_descriptor >= 0;
}

int CloseLinux( aFILE * file ){	
	return close( file->file_descriptor ) == 0;
}

void CleanupLinux(){
	// free the completion list
	free( completion_list );
	completion_list = NULL;
	ctx_id = NULL;
}

int FillAIOStruct( aFILE * file, aIORec * rec ){
// fill the request data structure
	rec->aio_cb = (iocb_t*) malloc( sizeof(iocb_t));
	if(rec->aio_cb == 0)
		return 0;

	memset(rec->aio_cb, 0, sizeof(iocb_t));
	if( rec->pos != CURRENT_POS ){
		offset_t tmppos = rec->pos;
		tmppos >>= 32;
		file->filep_high = tmppos;
		// clear high bits.  Is this really necessary?
		tmppos = rec->pos;
		tmppos <<= 32;
		tmppos >>= 32;
		file->filep_low = tmppos;
	}

//	rec->aio_cb->aio_data = current_id++;
	rec->aio_cb->aio_fildes = file->file_descriptor;
	rec->aio_cb->u.c.offset = file->filep_high;
	rec->aio_cb->u.c.offset <<= 32;
	rec->aio_cb->u.c.offset |= file->filep_low;
	rec->aio_cb->u.c.buf = rec->buf;
	rec->aio_cb->u.c.nbytes = rec->size * rec->count;
	
	return 1;
}

int WriteLinux( aFILE * file, aIORec * rec ){
        int req_error;
	struct iocb *request_array[] = { rec->aio_cb };
	if( FillAIOStruct( file, rec ) ){
		// request the io
		rec->aio_cb->aio_lio_opcode = IO_CMD_PWRITE;
		req_error = io_submit( ctx_id, 1, &rec->aio_cb );
		if(req_error != 1){
			printf("write_submit: io_submit res=%d [%s]\n", req_error, strerror(-req_error));
            printf( "aiocb->aio_fildes = %d\n", rec->aio_cb->aio_fildes );
            printf( "aiocb->u.c.offset = %llu\n", rec->aio_cb->u.c.offset );
            printf( "aiocb->u.c.buf = %lx\n", rec->aio_cb->u.c.buf );
            printf( "aiocb->u.c.nbytes = %llu\n", rec->aio_cb->u.c.nbytes );
            printf( "aiocb->aio_reqprio = %d\n", rec->aio_cb->aio_reqprio );
		}
		return req_error == 1;
	}
	return 0;
}

int ReadLinux( aFILE * file, aIORec * rec ){
	int req_error;
	struct iocb *request_array[] = { rec->aio_cb };
// fill the request data structure
	if( FillAIOStruct( file, rec ) ){
	// request the io
		rec->aio_cb->aio_lio_opcode = IO_CMD_PREAD;
		req_error = io_submit( ctx_id, 1, &rec->aio_cb );
        if(req_error != 1){
			printf("read_submit: io_submit res=%d [%s]\n", req_error, strerror(-req_error));
//                printf( "aiocb->aio_filedes = %d\n", rec->aio_cb->aio_filedes );
//                printf( "aiocb->aio_offset = %llu\n", rec->aio_cb->aio_offset );
//                printf( "aiocb->aio_buf = %lx\n", rec->aio_cb->aio_buf );
//                printf( "aiocb->aio_nbytes = %llu\n", rec->aio_cb->aio_nbytes );
                printf( "aiocb->aio_reqprio = %d\n", rec->aio_cb->aio_reqprio );
        }
		return req_error == 1;
	}
	return 0;
}


// PRECONDITION:  file->queuetail is not null
// simply queries wether the first request submitted to the file has
// completed yet.
int QueryLastCompleteLinux( aFILE * file ){
	int rval;
	int compI;
	completion_id_t *comp;
	struct io_event ioe;
	struct timespec zero_wait;

	zero_wait.tv_sec = 0;
	zero_wait.tv_nsec = 10000000;
	
	rval = io_getevents( ctx_id, 0, 1, &ioe, &zero_wait );
	if( rval == 1 ){
		completion_id_t *completion = (completion_id_t*)malloc( sizeof(completion_id_t) );
		completion->data = ioe.data;
		PushTailComp( completion_list, completion );
	}
	comp = completion_list->head;
	for( compI = 0; compI < completion_list->nitems; compI++ ){
		if( comp->data == ioe.data )
			break;
	}
	if( compI != completion_list->nitems ){
		RemoveItemComp( completion_list, comp );
		return 1; // success
	}
	return 0;	// hasn't completed yet
}

#endif