Php extension and embedding-resource data type 2. Complex data types stored in resource variables usually require memory allocation, CPU time, or network communication during initialization. However, the complex data types stored in resource variables, such as database connections, between requests, usually require memory allocation, CPU time, or network communication during initialization. However, to retain resources similar to database connections between requests, you must make them persistent. Whether resources are persistent is a factor that must be taken into account.
First, let's look at the memory allocation problem:When using php, emalloc is preferred because it is a version with recovery of malloc. However, persistent resources must exist between requests. For a file handle class resource, if you want to add a storage file name, you must add the following code to the header file:
typedef struct _php_sample_descriptor_data { char *filename; FILE *fp;} php_sample_descriptor_data;
Using this structure, you can store file names and file handle resources to share different requests.
Corresponding changes must be made in the source file:
Static void php_sample_descriptor_dtor (// This is the callback function for resource recycling, which is defined at the resource initialization. Zend_rsrc_list_entry * rsrc TSRMLS_DC) {php_sample_descriptor_data * fdata = (optional *) rsrc-> ptr; fclose (fdata-> fp); efree (fdata-> filename ); efree (fdata );}
This static function is used to recycle resources. you need to specify a callback when initializing resources.
The modified file opening function requires the following operations:
PHP_FUNCTION (sample_fopen) // modified fopen {random * fdata; FILE * fp; char * filename, * mode; int filename_len, mode_len; if (random (ZEND_NUM_ARGS () TSRMLS_CC, "ss", & filename, & filename_len, & mode, & mode_len) = FAILURE) {// Obtain the file name and length RETURN_NULL ();} if (! Filename_len |! Mode_len) {php_error_docref (NULL TSRMLS_CC, E_WARNING, "Invalid filename or mode length"); RETURN_FALSE;} fp = fopen (filename, mode); if (! Fp) {php_error_docref (NULL TSRMLS_CC, E_WARNING, "Unable to open % s using mode % s", filename, mode); RETURN_FALSE ;}Fdata = emalloc (sizeof (php_sample_descriptor_data); // allocate space for structures containing file resources and file names. fdata-> fp = fp; fdata-> filename = estrndup (filename, filename_len );ZEND_REGISTER_RESOURCE (return_value, fdata, le_sample_descriptor); // register resources}
You also need to modify the file write function fwrite:
PHP_FUNCTION(sample_fwrite){ php_sample_descriptor_data *fdata; zval *file_resource; char *data; int data_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &file_resource, &data, &data_len) == FAILURE ) { RETURN_NULL(); } ZEND_FETCH_RESOURCE(fdata, php_sample_descriptor_data*, &file_resource, -1, PHP_SAMPLE_DESCRIPTOR_RES_NAME, le_sample_descriptor); RETURN_LONG(fwrite(data, 1, data_len, fdata->fp));}
The sample_fclose function does not need to be changed because it does not operate on actual resources. The following function obtains the original file name from the resource:
PHP_FUNCTION(sample_fname){ php_sample_descriptor_data *fdata; zval *file_resource; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &file_resource) == FAILURE ) { RETURN_NULL(); } ZEND_FETCH_RESOURCE(fdata, php_sample_descriptor_data*, &file_resource, -1, PHP_SAMPLE_DESCRIPTOR_RES_NAME, le_sample_descriptor); RETURN_STRING(fdata->filename, 1);}
After the memory allocation is completed, it must be persistent.
Latency analysis structure:
For non-persistent resources, once the variables with resource IDs are unset or fallen out of scope, they are removed from EG (regular_list. The indexes used in EG (persistent_list) are key-value classes, and the elements are not automatically removed at the end of the request. It is eliminated only when zend_hash_del () is called or when the thread/process is completely disabled. EG (persistent_list) also has the dtor method, but is the second parameter of zend_register_list_descructors_ex. In general, non-persistent and persistent resources are registered into two types, and sometimes they can be combined into one. Add a persistent resource type in sample. c.
Static int le_sample_descriptor_persist; static void php_sample_descriptor_dtor_persistent (zend_rsrc_list_entry * rsrc TSRMLS_DC ){// This is a persistent resource destructor.Php_sample_descriptor_data * fdata = (php_sample_descriptor_data *) rsrc-> ptr;Fclose (fdata-> fp); pefree (fdata-> filename, 1); pefree (fdata, 1 );} PHP_MINIT_FUNCTION (sample) {le_sample_descriptor = zend_register_list_destructors_ex (php_sample_descriptor_dtor, NULL, PHP_SAMPLE_DESCRIPTOR_RES_NAME, module_number );Le_sample_descriptor_persist = zend_register_list_destructors_ex (NULL, role, PHP_SAMPLE_DESCRIPTOR_RES_NAME, module_number); // register a persistent resourceReturn SUCCESS ;}
The following fopen function is compatible with two types of persistent and non-persistent resources:
PHP_FUNCTION (sample_fopen) {parameters * fdata; FILE * fp; char * filename, * mode; int filename_len, mode_len; zend_bool persist = 0; if (parameters (ZEND_NUM_ARGS () TSRMLS_CC, "ss | B", & filename, & filename_len, & mode, & mode_len, & persist) = FAILURE) {RETURN_NULL ();} if (! Filename_len |! Mode_len) {php_error_docref (NULL TSRMLS_CC, E_WARNING, "Invalid filename or mode length"); RETURN_FALSE;} fp = fopen (filename, mode); if (! Fp) {php_error_docref (NULL TSRMLS_CC, E_WARNING, "Unable to open % s using mode % s", filename, mode); RETURN_FALSE;} if (! Persist) {// non-persistent resource fdata = emalloc (sizeof (php_sample_descriptor_data); fdata-> filename = estrndup (filename, filename_len ); // perform the following two steps: Apply for memory and assign values: fdata-> fp = fp; ZEND_REGISTER_RESOURCE (return_value, fdata, le_sample_descriptor);} else {// persistent resource list_entry le; char * hash_key; int hash_key_len; fdata = pemalloc (sizeof (bytes), 1); fdata-> filename = pemalloc (filename_len + 1, 1); memcpy (fdata-> filename, filename, filename_len + 1); fdata-> fp = fp; ZEND_REGISTER_RESOURCE (return_value, fdata, le_sample_descriptor_persist ); /* Store a copy in the persistent_list to Store a copy in the persistent_list */le. type = le_sample_descriptor_persist; le. ptr = fdata; hash_key_len = spprintf (& hash_key, 0, "sample_descriptor: % s", filename, mode); zend_hash_update (& EG (persistent_list), hash_key, hash_key_len + 1, (void *) & le, sizeof (list_entry), NULL); efree (hash_key );}}
For non-persistent Resources, an index with a given number is stored in the list with request dependency. Given a key-value type for persistent resources, this hashkey can be re-obtained in the following request. Then, the resource is put into the persistentlist. When a persistent resource out of scope, the EG (regular_list) destructor checks the registerlist destructor for le_sample_descriptro_persist. If it is NULL, no operation will be performed. This ensures that persistent resources are not released. When the resource is removed from EG (persistent_list), it is either the thread process has ended or it is intentionally deleted. At this time, we will find the persistent destructor.
The reason why the resource is applied for persistence is that other requests can
Reuse:
If you want to reuse persistent resources, you must use hash_key. when sample_fopen is called, the function will recreate the hash_key using the requested file name and mode, then try to find it in persistent_list.
PHP_FUNCTION (sample_fopen) {comment * fdata; FILE * fp; char * filename, * mode, * hash_key; int filename_len, mode_len, hash_key_len; zend_bool persist = 0; // Determine whether the list_entry * existing_file is persistent; if (values (ZEND_NUM_ARGS () TSRMLS_CC, "ss | B", & filename, & filename_len, & mode, & mode_len, & persist) = FAILURE) {RETURN_NULL ();} if (! Filename_len |! Mode_len) {php_error_docref (NULL TSRMLS_CC, E_WARNING, "Invalid filename or mode length"); RETURN_FALSE ;}/* Obtain a hash_key and try to find an opened file */hash_key_len = spprintf (& hash_key, 0, "sample_descriptor: % s", filename, mode ); if (zend_hash_find (& EG (persistent_list), hash_key, hash_key_len + 1, (void **) & existing_file) = SUCCESS) {/* the opened file handle resource */ZEND_REGISTER_RESOURCE (return_value, existing_file-> ptr, le_sample_descriptor_persist); efree (hash_key); return ;}Fp = fopen (filename, mode); if (! Fp) {php_error_docref (NULL TSRMLS_CC, E_WARNING, "Unable to open % s using mode % s", filename, mode); RETURN_FALSE;} if (! Persist) {fdata = emalloc (sizeof (bytes); fdata-> filename = estrndup (filename, filename_len); fdata-> fp = fp; ZEND_REGISTER_RESOURCE (return_value, fdata, le_sample_descriptor);} else {list_entry le; fdata = pemalloc (sizeof (php_sample_descriptor_data), 1); fdata-> filename = pemalloc (filename_len + 1, 1 ); memcpy (data-> filename, filename, filename_len + 1); fdata-> fp = fp; ZEND_REGISTER_RESOURCE (return_value, fdata, le_sample_descriptor_persist ); /* Store a copy in the persistent_list */le. type = le_sample_descriptor_persist; le. ptr = fdata;/* hash_key has already been created by now */zend_hash_update (& EG (persistent_list), hash_key, hash_key_len + 1, (void *) & le, sizeof (list_entry), NULL);} efree (hash_key );}
Note that all extensions use the same hash form to store resources, so naming is important. Generally, extensions and resource type names are used as prefixes.
Check resource availability:
Although resources such as files can be opened for a long time, such resources as remote network resources are problematic if they are not used between requests for a long time. Therefore, you must determine the availability before using a persistent resource.
If (zend_hash_find (& EG (persistent_list), hash_key, hash_key_len + 1, (void **) & socket) = SUCCESS) {if (php_sample_socket_is_alive (socket-> ptr )) {ZEND_REGISTER_RESOURCE (return_value, socket-> ptr, le_sample_socket); return;} zend_hash_del (& EG (persistent_list), hash_key, hash_key_len + 1 ); // calls the previously registered destructor here}
Bytes. However, the requests are retained for resources like database connection...