2016-09-20 5 views
5

में एक छोटे से पढ़ने को मजबूर करने के लिए एक रास्ता तलाश रहे हैं मैं लिनक्स में छोटे पढ़ने के उत्पादन की एक विधि की तलाश में हूं ताकि मैं उनके चारों ओर हैंडलिंग कोड का परीक्षण कर सकूं।लिनक्स

मेरे पास कई विधियां हैं जो निम्न स्तर पर फ़ाइल सिस्टम के भीतर फ़ाइल से पढ़ने के लिए pread/pread64 को कॉल करती हैं। ये उन स्थितियों को संभालने के लिए डिज़ाइन किए गए हैं जहां एक संक्षिप्त पठन होता है (बाइट पढ़ने की संख्या अनुरोध संख्या से कम है)।

मैंने उन परिस्थितियों को देखा है जहां संक्षिप्त पढ़ता है (नेटवर्क वाली फाइल सिस्टम में)।

आदर्श रूप से मैं एक ऐसी फाइल बनाने में सक्षम हूं जो एन बाइट्स को पढ़ने की अनुमति देगी और फिर एम बाइट्स का संक्षिप्त पठन होगा, इसके बाद सामान्य रूप से अपेक्षित पढ़ा जाएगा। यह यूनिट परीक्षण फ़ाइल/फ़ाइल सिस्टम पर इंगित करने की अनुमति देगा।

धन्यवाद!

+2

सबसे आसान, या कम से कम सबसे लचीला, शायद 'mkfifo() 'या' mknod()' के साथ नामित पाइप बनाना होगा। – Will

+0

एक 'कवर' फ़ंक्शन पर कॉल करें जो आमतौर पर प्रासंगिक 'read()' संस्करण को कॉल करता है और पूर्ण आकार देता है, लेकिन इसे मांग पर थोड़ी सी राशि वापस करने के लिए कॉन्फ़िगर किया जा सकता है। 'ssize_t tst_read (शून्य * बफर, आकार_टी आकार, int fd) {ssize_t nbytes = पढ़ें (बफर, आकार, एफडी); अगर (... उचित परीक्षण की स्थिति ...) nbytes - = 13; वापसी nbytes; } '। कुल्ला और प्रत्येक पढ़ने-जैसा फ़ंक्शन के लिए दोहराएं जिसे आपको परीक्षण करने की आवश्यकता है। –

+0

उह, हाँ, अगर आप सिर्फ पढ़ने के लिए कॉल को ही समाहित कर सकते हैं तो @ जोनाथन लेफ्लर ने सुझाव दिया है, * वह * सबसे अच्छा होगा :) – Will

उत्तर

2

यदि आप लाइब्रेरी कॉल (जिसे) को अवरुद्ध करना चाहते हैं, तो आप LD_PRELOAD के माध्यम से लोड की गई साझा ऑब्जेक्ट के साथ कॉल पर इंटरैप कर सकते हैं।

shortread.c:

gcc -shared [-m32|-m64] shortread.c -o libshortread.so 
फिर

:

की तरह कुछ के साथ
#include <sys/types.h> 
#include <dlfcn.h> 

#define MAX_FDS 1024 

static int short_read_array[ MAX_FDS ]; 

// #define these to match your system's values 
// (need to be really careful with header files since 
// getting open() declared would make things very 
// difficult - just try this with open(const char *, int, ...); 
// declared to see what I mean...) 
#define O_RDONLY 0 
#define O_WRONLY 1 
#define O_RDWR 2 

// note that the mode bits for read/write are 
// not a bitwise-or - they are distinct values 
#define MODE_BITS 3 

// it's much easier to *NOT* even deal with the 
// fact that open() is a varargs function 
// but that means probably having to do some 
// typedef's and #defines to get this to compile 

// typedef some function points to make things easier 
typedef int (*open_ptr_t)(const char *name, int flags, mode_t mode); 
typedef ssize_t (*read_ptr_t)(int fd, void *buf, size_t bytes); 
typedef int (*close_ptr_t)(int fd); 

// function points to the real IO library calls 
static open_ptr_t real_open = NULL; 
static read_ptr_t real_read = NULL; 
static close_ptr_t real_close = NULL; 

// this will return non-zero if 'filename' is a file 
// to cause short reads on 
static int shortReadsOnFd(const char *filename) 
{ 
    // add logic here based on the file name to 
    // return non-zero if you want to do 
    // short reads on this file 
    // 
    // return(1); 
    return(0); 
} 

// interpose on open() 
int open(const char *filename, int flags, mode_t mode) 
{ 
    static pthread_mutex_t open_mutex = PTHREAD_MUTEX_INITIALIZER; 
    int fd; 

    pthread_mutex_lock(&open_mutex); 
    if (NULL == real_open) 
    { 
     real_open = dlsym(RTLD_NEXT, "open"); 
    } 
    pthread_mutex_unlock(&open_mutex); 

    fd = real_open(filename, flags, mode); 
    if ((-1 == fd) || (fd >= MAX_FDS)) 
    { 
     return(fd); 
    } 

    int mode_bits = flags & MODE_BITS; 

    // if the file can be read from, check if this is a file 
    // to do short reads on 
    if ((O_RDONLY == mode_bits) || (O_RDWR == mode_bits)) 
    { 
     short_read_array[ fd ] = shortReadsOnFd(filename); 
    } 

    return(fd); 
} 

ssize_t read(int fd, void *buffer, size_t bytes) 
{ 
    static pthread_mutex_t read_mutex = PTHREAD_MUTEX_INITIALIZER; 

    if ((fd < MAX_FDS) && (short_read_array[ fd ])) 
    { 
     // read less bytes than the caller asked for 
     bytes /= 2; 
     if (0 == bytes) 
     { 
      bytes = 1; 
     } 
    } 

    pthread_mutex_lock(&read_mutex); 
    if (NULL == real_read) 
    { 
     real_read = dlsym(RTLD_NEXT, "read"); 
    } 
    pthread_mutex_unlock(&read_mutex); 

    return(real_read(fd, buffer, bytes)); 
} 

int close(int fd) 
{ 
    static pthread_mutex_t close_mutex = PTHREAD_MUTEX_INITIALIZER; 

    pthread_mutex_lock(&close_mutex); 
    if (NULL == real_close) 
    { 
     real_close = dlsym(RTLD_NEXT, "close"); 
    } 
    pthread_mutex_unlock(&close_lock); 

    if (fd < MAX_FDS) 
    { 
     short_read_array[ fd ] = 0; 
    } 

    return(real_close(fd)); 
} 

संकलित

export LD_PRELOAD=/path/to/libshortread.so 

इस तरह के एक LD_PRELOAD साथ अत्यंत सावधान रहें - प्रक्रिया पेड़ में सभी प्रक्रियाओं पुस्तकालय लोड करने के लिए मजबूर किया जाएगा। यदि 32-बिट लाइब्रेरी लोड करने की कोशिश करने के लिए मजबूर किया गया है, तो एक 64-बिट प्रक्रिया को 64-बिट लाइब्रेरी लोड करने के लिए 32-बिट प्रक्रिया चलाने में विफल रहेगा। आप ऊपर दिए गए स्रोत में एक init फ़ंक्शन जोड़ सकते हैं जो कुछ हद तक नियंत्रित करने के लिए LD_PRELOAD पर्यावरण चर (या इसे कुछ हानिरहित पर सेट करता है) को हटा देता है।

यदि आपको open() के लिए ध्वज का उपयोग करता है तो आपको शायद सावधान रहना होगा। पढ़ने वाले बाइट्स की संख्या को संशोधित करने से कुछ लिनक्स फ़ाइल सिस्टम और/या कार्यान्वयन के लिए प्रत्यक्ष आईओ तोड़ सकता है, क्योंकि केवल पेज-आकार आईओ ऑपरेशंस समर्थित हो सकते हैं।

और यह कोड केवल read() को संभालता है। आपको creat() से निपटने की भी आवश्यकता हो सकती है। pread(), readat(), aio_read(), और lio_listio(), (और यहां तक ​​कि कुछ अन्य जिन्हें मैं इस समय याद नहीं कर सकता) हालांकि यह स्वीकार्य रूप से बहुत संभव नहीं है। और 32-बिट प्रक्रियाओं से सावधान रहें जो बड़ी फ़ाइलों को संभालते हैं। यह थोड़ी देर के बाद से मैंने उनसे निपटाया है, लेकिन मुझे याद आती है कि बदसूरत हो सकती है।

एक और चेतावनी कॉल ऐसे fopen() और fread() रूप open() और read() पुस्तकालय कॉल फोन नहीं कर सकते हैं और सीधे प्रासंगिक सिस्टम कॉल जारी कर सकता है है। उस स्थिति में, आप आसानी से उन कॉल के व्यवहार को संशोधित करने में सक्षम नहीं होंगे। एसटीडीआईओ-आधारित कॉल के पूरे परिवार पर इंटरपोज़ करना जो fgets() जैसे डेटा पढ़ सकता है, चीजों को तोड़ने के बिना करना मुश्किल हो सकता है।

और यदि आप जानते हैं आपका आवेदन एकल-थ्रेडेड हैं, तो आप म्यूटेक्स को छोड़ सकते हैं।

+0

धन्यवाद एंड्रयू! एक अद्भुत विस्तृत वर्णन और समाधान। – CoreyP

1

अंत में मैं mkfifo() का उपयोग कर समाधान के साथ गया।

मैं नामित पाइप बना देता हूं, फिर एक लेखक से कनेक्ट करता हूं (और इसे जावा से उपयोग करने के लिए जेएनआई लाइब्रेरी में लपेटकर समाप्त करता हूं)। अतुल्यकालिक लेखक को सही समय पर डेटा लिखने के लिए कहा जा सकता है, जिस बिंदु पर कनेक्टेड रीडर को कुल अनुरोधित संख्या के बजाय केवल उपलब्ध/लिखित बाइट मिलते हैं।